Spring Boot JPA CrudRepository选择性更新 - 只有一些属性

时间:2017-03-13 20:53:20

标签: spring hibernate spring-boot spring-data spring-data-jpa

在使用Hibernate和Spring Boot JPA时,我注意到当尝试在扩展Spring的CrudRepository接口的存储库工件中实现更新方法时,必须将要更新的整个实体对象传递给这样的更新方法。直觉上看起来很浪费,我想知道什么是一种简洁的方法让Spring Data / JPA假设只传递的那些值需要更新并保留那些未传递的值。

这是现在的服务方法,

   public void updateCustomer(Long id, Customer customer) throws Exception {
        customerRepository.save(customer);
    }

1 个答案:

答案 0 :(得分:1)

在JPA中,您传递实体,框架会确定您更改了哪些属性。如果您还不知道这一点,我建议您花一点时间阅读JPA的基础知识。从表面上看,JPA看起来既简单又平易近人,但如果您不了解它所基于的原则,您最终会花费大量时间进行调试并使用Google搜索来破译错误消息。

当实体为managed时,JPA会在加载对象时获取该对象的副本,然后将其与传递给save/persist的版本进行比较,并找出应更新的列。这使得易于使用的开发人员模型成为您(通常)不必考虑实体更改的原因。

正如Rob建议的那样,您可能认为加载单个实体来更改单个属性是浪费,但情况并非总是如此。默认情况下,EclipseLink和Hibernate都使用共享(第二级)缓存,因此如果已经加载了实体,则可以从内存而不是DB加载它,并且一旦修改了实体,JPA就会比较内存中的两个对象,生成修改列所需的SQL。

有时您需要优化JPA代码(但只有在您测量了哪些操作很慢时)。经典方案是批量删除/更新,您不希望JPA花时间阅读/复制/管理您要删除/更新的实体。在这些情况下,您可以使用删除或更新查询,而不是加载实体并调用EntityManager.remove()或修改事务内的实体。但是,您应该知道这会绕过EntityListeners和级联指令,因为这些只是为托管实体调用。