INSERT Statement in JPA – JPA中的INSERT语句

最后修改: 2018年 12月 30日

中文/混合/英文(键盘快捷键:t)

1. Overview

1.概述

In this quick tutorial, we’ll learn how to perform an INSERT statement on JPA objects.

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

For more information about Hibernate in general, check out our comprehensive guide to JPA with Spring and introduction to Spring Data with JPA for deep dives into this topic.

有关 Hibernate 的更多信息,请查看我们全面的 JPA 与 Spring 的指南Spring Data 与 JPA 的介绍,以深入了解这一主题。

2. Persisting Objects in JPA

2.在JPA中持久化对象

In JPA, every entity going from a transient to managed state is automatically handled by the EntityManager.

在JPA中,每个实体从暂存状态到管理状态都是由EntityManager自动处理。

The EntityManager checks whether a given entity already exists and then decides if it should be inserted or updated. Because of this automatic management, the only statements allowed by JPA are SELECT, UPDATE and DELETE.

EntityManager检查某个实体是否已经存在,然后决定是否应该插入或更新。由于这种自动管理,tJPA所允许的语句只有SELECT、UPDATE和DELETE。

In the examples below, we’ll look at different ways of managing and bypassing this limitation.

在下面的例子中,我们将看看管理和绕过这一限制的不同方法。

3. Defining a Common Model

3.定义一个共同的模式

Now, let’s start by defining a simple entity that we’ll use throughout this tutorial:

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

@Entity
public class Person {

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

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

Also, let’s define a repository class that we’ll use for our implementations:

另外,让我们定义一个资源库类,我们将使用它来实现。

@Repository
public class PersonInsertRepository {

    @PersistenceContext
    private EntityManager entityManager;

}

Additionally, we’ll apply the @Transactional annotation to handle transactions automatically by Spring. This way, we won’t have to worry about creating transactions with our EntityManager, committing our changes, or performing rollback manually in the case of an exception.

此外,我们将应用@Transactional注解,以便由Spring自动处理事务。这样,我们就不必担心用我们的EntityManager创建事务,提交我们的更改,或者在出现异常的情况下手动执行回滚。

4. createNativeQuery

4.createNativeQuery

For manually created queries, we can use the EntityManager#createNativeQuery method. It allows us to create any type of SQL query, not only ones supported by JPA. Let’s add a new method to our repository class:

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

@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();
}

With this approach, we need to define a literal query including names of the columns and set their corresponding values.

采用这种方法,我们需要定义一个包括列名的字面查询,并设置其相应的值。

We can now test our repository:

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

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

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

In our test, every operation attempts to insert a new entry into our database. Since we tried to insert two entities with the same id, the second insert operation fails by throwing a PersistenceException.

在我们的测试中,每个操作都试图向我们的数据库插入一个新条目。由于我们试图插入两个具有相同id的实体,第二个插入操作失败,抛出一个PersistenceException

The principle here is the same if we are using Spring Data’s @Query.

如果我们使用Spring Data的@Query.,这里的原理是一样的。

5. persist

5.persist

In our previous example, we created insert queries, but we had to create literal queries for each entity. This approach is not very efficient and results in a lot of boilerplate code.

在我们之前的例子中,我们创建了插入查询,但我们不得不为每个实体创建字面查询。这种方法效率不高,而且会导致大量的模板代码。

Instead, we can make use of the persist method from EntityManager.

相反,我们可以利用来自EntityManagerpersist方法。

As in our previous example, let’s extend our repository class with a custom method:

就像我们之前的例子一样,让我们用一个自定义的方法来扩展我们的资源库类。

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

Now, we can test our approach again:

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

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

In contrast to using native queries, we don’t have to specify column names and corresponding values. Instead, EntityManager handles that for us.

与使用本地查询相比,我们不需要指定列名和相应的值。相反,EntityManager为我们处理这些。

In the above test, we also expect EntityExistsException to be thrown instead of its superclass PersistenceException which is more specialized and thrown by persist.

在上述测试中,我们也希望抛出EntityExistsException,而不是其超类PersistenceException,后者更专业,由persist抛出。

On the other hand, in this example, we have to make sure that we call our insert method each time with a new instance of Person. Otherwise, it will be already managed by EntityManager, resulting in an update operation.

另一方面,在这个例子中,我们必须确保我们每次都用一个新的Person.实例来调用我们的插入方法,否则,它将已经被EntityManager管理,导致更新操作。

6. Conclusion

6.结论

In this article, we illustrated ways to perform insert operations on JPA objects. We looked at examples of using a native query, as well as using EntityManager#persist to create custom INSERT statements.

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

As always, the complete code used in this article is available over on GitHub.

一如既往,本文中使用的完整代码可在GitHub上找到。