@DynamicUpdate with Spring Data JPA – 用Spring Data JPA的@DynamicUpdate

最后修改: 2019年 7月 22日

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

1. Overview

1.概述

When we use Spring Data JPA with Hibernate, we can use the additional features of Hibernate as well. @DynamicUpdate is one such feature.

当我们将Spring Data JPA与Hibernate一起使用时,我们也可以使用Hibernate的额外功能。@DynamicUpdate就是这样一个功能。

@DynamicUpdate is a class-level annotation that can be applied to a JPA entity. It ensures that Hibernate uses only the modified columns in the SQL statement that it generates for the update of an entity.

@DynamicUpdate是一个可以应用于JPA实体的类级注解。它确保Hibernate在为实体的更新生成的SQL语句中只使用修改过的列

In this article, we’ll take a look at the @DynamicUpdate annotation, with the help of a Spring Data JPA example.

在这篇文章中,我们将借助一个Spring Data JPA示例,来看看@DynamicUpdate注解。

2. JPA @Entity

2.JPA @Entity

When an application starts, Hibernate generates the SQL statements for CRUD operations of all the entities. These SQL statements are generated once and are cached, in memory, to improve the performance.

当一个应用程序启动时,Hibernate为所有实体的CRUD操作生成SQL语句。这些SQL语句只生成一次,并被缓存在内存中,以提高性能。

The generated SQL update statement includes all the columns of an entity. In case we update an entity, the values of the modified columns are passed to the SQL update statement. For the columns that are not updated, Hibernate uses their existing values for the update.

生成的SQL更新语句包括一个实体的所有列。如果我们更新一个实体,修改后的列的值将被传递到SQL更新语句中。对于那些没有被更新的列,Hibernate使用它们现有的值进行更新。

Let’s try to understand this with an example. First, let’s consider a JPA entity named Account:

让我们试着用一个例子来理解这个问题。首先,让我们考虑一个名为Account的JPA实体。

@Entity
public class Account {

    @Id
    private int id;

    @Column
    private String name;

    @Column
    private String type;

    @Column
    private boolean active;

    // Getters and Setters
}

Next, let’s write a JPA repository for the Account entity:

接下来,让我们为Account实体编写一个JPA存储库。

@Repository
public interface AccountRepository extends JpaRepository<Account, Integer> {
}

Now, we’ll use the AccountRepository to update the name field of an Account object:

现在,我们将使用AccountRepository来更新一个Account对象的name字段。

Account account = accountRepository.findOne(ACCOUNT_ID);
account.setName("Test Account");
accountRepository.save(account);

After we execute this update, we can verify the generated SQL statement. The generated SQL statement will include all the columns of Account:

在我们执行这个更新后,我们可以验证生成的SQL语句。生成的SQL语句将包括Account的所有列。

update Account set active=?, name=?, type=? where id=?

3. JPA @Entity with @DynamicUpdate

3.JPA @Entity@DynamicUpdate

We’ve seen that even though we’ve modified the name field only, Hibernate has included all the columns in the SQL statement.

我们看到,尽管我们只修改了name字段,但Hibernate已经在SQL语句中包含了所有的列。

Now, let’s add the @DynamicUpdate annotation to the Account entity:

现在,让我们将@DynamicUpdate注解添加到Account实体。

@Entity
@DynamicUpdate
public class Account {
    // Existing data and methods
}

Next, let’s run the same update code we used in the previous section. We can see that the SQL generated by Hibernate, in this case, includes only the name column:

接下来,让我们运行我们在上一节中使用的同样的更新代码。我们可以看到,在这种情况下,由Hibernate生成的SQL只包括name列。

update Account set name=? where id=?

So, what happens when we use @DynamicUpdate on an entity?

那么,当我们在一个实体上使用@DynamicUpdate时会发生什么呢

Actually, when we use @DynamicUpdate on an entity, Hibernate does not use the cached SQL statement for the update. Instead, it will generate a SQL statement each time we update the entity. This generated SQL includes only the changed columns.

实际上,当我们在实体上使用@DynamicUpdate时,Hibernate不会使用缓存的SQL语句进行更新。相反,它将在我们每次更新实体时生成一条SQL语句。这个生成的SQL语句只包括变化的列

In order to find out the changed columns, Hibernate needs to track the state of the current entity. So, when we change any field of an entity, it compares the current and the modified states of the entity.

为了找出变化的列,Hibernate需要跟踪当前实体的状态。因此,当我们改变一个实体的任何字段时,它会比较该实体的当前状态和修改状态。

This means that @DynamicUpdate has a performance overhead associated with it. Therefore, we should only use it when it’s actually required.

这意味着@DynamicUpdate有一个与之相关的性能开销。因此,我们应该只在真正需要的时候使用它。

Certainly, there are a few scenarios where we should use this annotation — for example, if an entity represents a table that has a large number of columns and only a few of these columns are required to be updated frequently. Also, when we use version-less optimistic locking, we need to use @DynamicUpdate.

当然,在少数情况下,我们应该使用这个注解–例如,如果一个实体代表一个有大量列的表,而这些列中只有少数需要经常更新。另外,当我们使用无版本的乐观锁时,我们需要使用@DynamicUpdate

4. Conclusion

4.总结

In this tutorial, we’ve looked into the @DynamicUpdate annotation of Hibernate. We’ve used an example of Spring Data JPA to see @DynamicUpdate in action. Also, we’ve discussed when we should use this feature and when we should not.

在本教程中,我们研究了Hibernate的@DynamicUpdate注解。我们使用了一个Spring Data JPA的例子来观察@DynamicUpdate的运行。此外,我们还讨论了什么时候应该使用这个特性,什么时候不应该。

As always, the complete code examples used in this tutorial are available over on Github.

一如既往,本教程中所使用的完整代码示例可在Github上获得