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

2022-08-31 05:12:38

好吧,这个问题几乎说明了一切。使用JPARepository如何更新实体?

JPARepository只有一个保存方法,它不会告诉我它是否实际上是在创建或更新。例如,我将一个简单的 Object 插入到数据库 User,它有三个字段:、 和 :firstnamelastnameage

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

然后我简单地调用 ,此时它实际上是插入到数据库中:save()

 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);

目前为止,一切都好。现在我想更新这个用户,比如说改变他的年龄。为此,我可以使用Query,QueryDSL或NamedQuery,等等。但是,考虑到我只想使用spring-data-jpa和JPARepository,我如何告诉它我想要做更新而不是插入?

具体来说,我如何告诉spring-data-jpa具有相同用户名和名字的用户实际上是相等的,并且应该更新现有实体?覆盖相等并不能解决这个问题。


答案 1

实体的标识由其主键定义。由于 和 不是主键的一部分,因此如果 s 不同,则不能告诉 JPA 将具有相同 s 和 s 的 s 视为相等。firstnamelastnameUserfirstnamelastnameuserId

因此,如果要更新由其和 标识的,则需要通过查询找到该查询,然后更改找到的对象的相应字段。这些更改将在事务结束时自动刷新到数据库中,因此您无需执行任何操作即可显式保存这些更改。UserfirstnamelastnameUser

编辑:

也许我应该详细阐述JPA的整体语义。有两种主要方法来设计持久性 API:

  • 插入/更新方法。当您需要修改数据库时,您应该显式调用持久性 API 的方法:调用以插入对象,或将对象的新状态保存到数据库中。insertupdate

  • 工作单元方法。在本例中,您有一组由持久性库管理的对象。您对这些对象所做的所有更改都将在工作单元结束时(即在典型情况下在当前事务结束时)自动刷新到数据库中。当需要将新记录插入数据库时,可以管理相应的对象。托管对象由其主键标识,因此,如果将具有预定义主键的对象设置为托管对象,则该对象将与同一 ID 的数据库记录相关联,并且此对象的状态将自动传播到该记录。

JPA遵循后一种方法。 在Spring Data中,JPA由普通的JPA支持,因此它使您的实体如上所述进行管理。这意味着调用具有预定义id的对象将更新相应的数据库记录而不是插入新的数据库记录,并且还解释了为什么不调用。save()merge()save()save()create()


答案 2

由于@axtavt的答案侧重于不JPAspring-data-jpa

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

Spring-data-jpa支持更新操作。
您必须在存储库接口中定义该方法,并使用 和 对其进行注释。@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用于定义自定义查询,并用于告知此查询是更新操作,不需要 。@Modifyingspring-data-jpaexecuteUpdate()executeQuery()

您可以指定其他返回类型:
- 正在更新的记录数。
- 如果存在正在更新的记录,则为 true。否则,为假。intboolean


注意:在事务中运行此代码。


推荐