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

新手上路,请多包涵

好吧,这个问题几乎说明了一切。使用 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);

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

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

原文由 Eugene 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 1.1k
2 个回答

实体的身份由它们的主键定义。 Since firstname and lastname are not parts of the primary key, you cannot tell JPA to treat User s with the same firstname s and lastname s 相同,如果它们不同 userId s。

So, if you want to update a User identified by its firstname and lastname , you need to find that User by a query,然后更改您找到的对象的适当字段。这些更改将在事务结束时自动刷新到数据库,因此您无需执行任何操作来显式保存这些更改。

编辑:

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

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

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

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

原文由 axtavt 发布,翻译遵循 CC BY-SA 4.0 许可协议

由于@axtavt 的回答集中在 JPA 而不是 spring-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 is for defining custom query and @Modifying is for telling spring-data-jpa that this query is an update operation and it requires executeUpdate() not executeQuery()

您可以将返回类型指定为 int ,其中包含正在更新的记录数。


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

原文由 hussachai 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题