1.概述

在本快速教程中,我们将学习如何在JPA对象上执行INSERT语句。

有关总体上有关Hibernate的更多信息,请查看我们的Spring JPA综合指南和JPA Spring Data简介,以深入研究该主题。

2.在JPA中保留对象

在JPA中,从瞬态到托管状态的每个实体都由EntityManager自动处理。

EntityManager检查给定的实体是否已经存在,然后决定是否应插入或更新该实体。由于这种自动管理,JPA允许的唯一语句是SELECT,UPDATE和DELETE。

在下面的示例中,我们将研究管理和绕过此限制的不同方法。

3.定义通用模型

现在,让我们开始定义一个简单的实体,我们将在本教程中使用它:

1
2
3
4
5
6
7
8
9
10

@Entity
public class Person {

    @Id
    private Long id;
    private String firstName;
    private String lastName;

    // standard getters and setters, default and all-args constructors
}

另外,让我们定义一个用于实现的存储库类:

1
2
3
4
5
6
7

@Repository
public class PersonInsertRepository {

    @PersistenceContext
    private EntityManager entityManager;

}

另外,我们将应用@Transactional批注来由Spring自动处理事务。这样,我们就不必担心使用ourEntityManager创建事务,提交更改或在发生异常情况下手动执行回滚。

4.createNativeQuery

对于手动创建的查询,我们可以使用EntityManager#createNativeQuery方法。它允许我们创建任何类型的SQL查询,而不仅仅是JPA支持的查询。让我们向存储库类添加一个新方法:

1
2
3
4
5
6
7
8

@Transactional
public void insertWithQuery(Person person) {
    entityManager.createNativeQuery("INSERT INTO person (id, first_name, last_name) VALUES (?,?,?)")
      .setParameter(1, person.getId())
      .setParameter(2, person.getFirstName())
      .setParameter(3, person.getLastName())
      .executeUpdate();
}

使用这种方法,我们需要定义一个包含列名的文字查询并设置它们的相应值。

现在我们可以测试我们的存储库:

1
2
3
4
5
6
7
8
9

@Test
public void givenPersonEntity_whenInsertedTwiceWithNativeQuery_thenPersistenceExceptionExceptionIsThrown() {
    Person person = new Person(1L,"firstname","lastname");

    assertThatExceptionOfType(PersistenceException.class).isThrownBy(() -> {
        personInsertRepository.insertWithQuery(PERSON);
        personInsertRepository.insertWithQuery(PERSON);
    });
}

在我们的测试中,每个操作都尝试将新条目插入我们的数据库。由于我们尝试插入具有相同ID的两个实体,因此第二个插入操作会因抛出aPersistenceException而失败。

如果我们使用Spring Data的@Query,这里的原理是相同的。

5.坚持

在前面的示例中,我们创建了插入查询,但是必须为每个实体创建文字查询。这种方法不是很有效,并且会导致大量样板代码。

相反,我们可以使用来自EntityManager的持久方法。

与之前的示例一样,让我们??使用自定义方法扩展存储库类:

1
2
3
4

@Transactional
public void insertWithEntityManager(Person person) {
    this.entityManager.persist(person);
}

现在,我们可以再次测试我们的方法:

1
2
3
4
5
6
7

@Test
public void givenPersonEntity_whenInsertedTwiceWithEntityManager_thenEntityExistsExceptionIsThrown() {
    assertThatExceptionOfType(EntityExistsException.class).isThrownBy(() -> {
        personInsertRepository.insertWithEntityManager(new Person(1L,"firstname","lastname"));
        personInsertRepository.insertWithEntityManager(new Person(1L,"firstname","lastname"));
    });
}

与使用本机查询相反,我们不必指定列名和相应的值。而是由EntityManager为我们处理。

在上面的测试中,我们还希望抛出EntityExistsException而不是它的superclassPersistenceException,它是由persist更为专门化和抛出的。

另一方面,在此示例中,我们必须确保每次使用新的Person实例调用插入方法,否则它将已经由EntityManager管理,从而导致更新操作。

六,结论

在本文中,我们说明了对JPA对象执行插入操作的方法。我们查看了使用本机查询以及使用EntityManager#persist创建自定义INSERT语句的示例。