在 Spring Boot JPA 中使用 Hibernate 时,我注意到当尝试在扩展 Spring 的 CrudRepository 接口(interface)的存储库工件中实现更新方法时,必须将要更新的整个实体对象传递给这样的更新方法。只是直觉上这似乎很浪费,我想知道什么是让 Spring Data/JPA 假设只有那些传入的值需要更新并且让那些未传入的值保持不变的干净方法。
这是目前的服务方式,
public void updateCustomer(Long id, Customer customer) throws Exception {
customerRepository.save(customer);
}
最佳答案
在 JPA 中,您传递实体,框架会计算出您更改了哪些属性。如果您还不知道这一点,我建议您多花一点时间阅读 JPA 的基础知识。从表面上看,JPA 看起来简单易懂,但如果您不了解其构建的原理,您最终将花费大量时间进行调试和谷歌搜索来破译错误消息。
当实体是 managed JPA 将在加载对象时获取该对象的副本,然后将其与传递给 save/persist
的版本进行比较。并找出应该更新哪些列。这形成了一个易于使用的开发人员模型,您(通常)不必考虑对实体的更改。
您可能认为,正如 Rob 所建议的那样,加载单个实体来更改单个属性是一种浪费,但情况并非总是如此。 EclipseLink 和 Hibernate 默认使用共享(二级)缓存,所以如果实体已经加载,它可能从内存而不是数据库加载,一旦你修改了实体,JPA 会比较内存中的两个对象并生成修改列所需的 SQL。
有时您需要优化 JPA 代码(但仅当您测量了哪些操作较慢时)。一个经典的场景是批量删除/更新,您不希望 JPA 花时间阅读/复制/管理您正在删除/更新的实体。在这些情况下,您可以使用删除或更新查询,而不是加载实体并调用 EntityManager.remove()
或修改事务中的实体。但是,您应该知道这会绕过 EntityListeners 和级联指令,因为它们仅被托管实体调用。
关于Spring Boot JPA CrudRepository 选择性更新 - 只有一些属性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42773211/