如何使用spring-data-jpa更新实体?

那么问题几乎说了一切。 使用JPARepository如何更新实体?

JPARepository只有一个保存方法,它不会告诉我它是实际创build还是更新。 例如,我向数据库用户插入一个简单的对象,它有三个字段:名字和姓氏和年龄:

@Entity public class User { private String firstname; private String lastname; //Setters and getters for age omitted, but they are the same as with firstname and lastname. private int age; @Column public String getFirstname() { return firstname; } public void setFirstname(String firstname) { this.firstname = firstname; } @Column public String getLastname() { return lastname; } public void setLastname(String lastname) { this.lastname = lastname; } private long userId; @Id @GeneratedValue(strategy=GenerationType.AUTO) public long getUserId(){ return this.userId; } public void setUserId(long userId){ this.userId = userId; } } 

然后,我简单地“保存”,这实际上是一个插入:

  User user1 = new User(); user1.setFirstname("john"); user1.setLastname("dew"); user1.setAge(16); userService.saveUser(user1);// This call is actually using the JPARepository: userRepository.save(user); 

好吧,一切都很好。 现在我想更新这个用户,说改变他的年龄。 那么我可以使用查询,无论是QueryDSL或NamedQuery。 但是,考虑到我只是想使用spring-data-jpa和JPARepository,我该如何告诉它,而不是插入我想要更新?

具体如何告诉spring-data-jpa具有相同用户名和名字的用户实际上是EQUAL并且应该更新实体。 重写等于没有工作。

谢谢!

实体的身份由其主键定义。 由于firstnamelastname不是主键的组成部分,因此如果用户名具有不同的用户userId ,则不能将JPA视为具有相同firstnamelastnameUser

所以,如果你想更新一个firstnamelastname标识的User ,你需要通过查询来find这个User ,然后改变你find的对象的相应的字段。 这些更改将在事务结束时自动刷新到数据库,以便您不需要执行任何操作来显式保存这些更改。

编辑:

也许我应该详细说明JPA的整体语义。 有两种主要的devise持久性API的方法:

  • 插入/更新方法 。 当你需要修改数据库时,你应该明确地调用持久化API的方法:你调用insert来插入一个对象,或者update来保存对象的新的状态到数据库。

  • 工作单位方法 。 在这种情况下,您有一组由持久性库pipe理的对象。 您对这些对象所做的所有更改将在工作单元末尾自动刷新到数据库(即在典型情况下的当前事务结束时)。 当您需要将新logging插入到数据库时,可以pipe理相应的对象。 托pipe对象由其主键标识,因此,如果您使用托pipe的预定义主键创build对象,它将与同一个标识的数据库logging关联,并且此对象的状态将自动传播到该logging。

JPA遵循后面的方法。 Spring Data中的save() JPA由纯JPA中的merge()支持,因此它使您的实体按上述方式进行pipe理 。 这意味着对具有预定义id的对象调用save()将更新相应的数据库logging,而不是插入新的数据库logging,也解释了为什么save()不称为create()

由于@axtavt的答案侧重于JPA而不是spring-data-jpa

要通过查询来更新实体,保存效率并不高,因为它需要两个查询,可能查询的代价可能非常昂贵,因为它可能会join其他表并加载任何具有fetchType=FetchType.EAGER

Spring-data-jpa支持更新操作。
您必须在Repository接口中定义该方法,并使用@Query@Modifying对其进行注释。

 @Modifying @Query("update User u set u.firstname = ?1, u.lastname = ?2 where u.id = ?3") void setUserInfoById(String firstname, String lastname, Integer userId); 

@Query用于定义自定义查询, @Modifying用于告诉spring-data-jpa这个查询是一个更新操作,它需要executeUpdate()而不是executeQuery()

使用spring-data-jpa save(),我遇到了和@DtechNet一样的问题。 我的意思是每个保存()是创build新的对象,而不是更新。 为了解决这个问题,我不得不在实体和相关表中添加“版本”字段。

这就是我解决问题的方法:

 User inbound = ... User existing = userRepository.findByFirstname(inbound.getFirstname()); if(existing != null) inbound.setId(existing.getId()); userRepository.save(inbound);