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

问题

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

JPARepository只有一个保存方法,它没有告诉我它是否实际创建或更新。例如,我将一个简单的Object插入数据库User,它有三个字段:firstname和lastname以及age:

@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,我都可以使用Query。但是,考虑到我只想使用spring-data-jpa和JPARepository,我该如何告诉它而不是插入我想要进行更新?

具体来说,我如何告诉spring-data-jpa具有相同用户名和名字的用户实际上是EQUAL并且它应该更新实体。压倒平等不起作用。

谢谢!


#1 热门回答(123 赞)

实体的标识由其主键定义。由于firstnamelastname不是主键的一部分,如果它们具有不同的userId,则不能告诉JPA将相同的firstnamelastname视为相同的User

因此,如果要更新由其firstnamelastname标识的aUser,则需要通过查询找到该User,然后更改找到的对象的相应字段。这些更改将在事务结束时自动刷新到数据库,因此你无需执行任何操作即可显式保存这些更改。
编辑:
也许我应该详细说明JPA的整体语义。设计持久性API有两种主要方法:

  • 插入/更新方法。当你需要修改数据库时,应该显式调用持久性API的方法:调用insert来插入对象,或者更新以将对象的新状态保存到数据库。
  • 工作单元方法。在这种情况下,你有一组由持久性库管理的对象。你对这些对象所做的所有更改将在工作单元结束时自动刷新到数据库(即在典型情况下在当前事务结束时)。当你需要将新记录插入数据库时​​,可以管理相应的对象。托管对象由其主键标识,因此,如果你使用预定义的主键托管对象,则它将与具有相同ID的数据库记录关联,并且此对象的状态将自动传播到该记录。

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


#2 热门回答(69 赞)

由于@axtavt的回答集中于JPAnotspring-data-jpa

要通过查询来更新实体,那么保存效率不高,因为它需要两个查询,并且查询可能非常昂贵,因为它可能会加入其他表并加载任何具有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用于tellspring-data-jpa此查询是更新操作,它需要executeUpdate()notexecuteQuery()


#3 热门回答(6 赞)

使用spring-data-jpa save(),我遇到了与@DtechNet相同的问题。我的意思是每个save()都在创建新对象而不是更新。为了解决这个问题,我不得不将"版本"添加到实体和相关表中。