首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何使用spring-data-jpa更新实体?

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

Stack Overflow用户
提问于 2012-08-09 18:33:44
回答 12查看 564.9K关注 0票数 256

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

JPARepository只有一个保存方法,它不会告诉我它实际上是在创建还是在更新。例如,我向数据库用户插入一个简单的对象,该对象有三个字段:firstnamelastnameage

代码语言:javascript
复制
 @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(),在这一点上,它实际上是对数据库的插入:

代码语言:javascript
复制
 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具有相同用户名和名字的用户实际上是相等的,并且现有实体应该被更新?重写equals并没有解决这个问题。

EN

回答 12

Stack Overflow用户

回答已采纳

发布于 2012-08-09 18:43:42

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

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

编辑:

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

  • insert/update接近。当您需要修改数据库时,您应该显式地调用persistence API的方法:调用insert来插入对象,或者调用update来将对象的新状态保存到database.
  • Unit of Work approach。在这种情况下,您有一组由持久化库管理的对象。您对这些对象所做的所有更改将在工作单元结束时(通常情况下是在当前事务结束时)自动刷新到数据库中。当您需要向数据库中插入新记录时,您可以使相应的对象成为托管对象。托管对象由其主键标识,因此,如果使用预定义主键进行管理,则该对象将与具有相同id的数据库记录相关联,并且此对象的状态将传播到该记录automatically.

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

票数 251
EN

Stack Overflow用户

发布于 2015-07-01 06:29:00

因为@axtavt的答案关注的是JPA而不是spring-data-jpa

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

Spring-data-jpa支持更新操作。

您必须在Repository中定义该方法,并使用@Query@Modifying对其进行注释。

代码语言:javascript
复制
@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()

您可以指定其他返回类型:

int -正在更新的记录数。

boolean -如果有正在更新的记录,则为true。否则为false。

注意:在Transaction中运行此代码。

票数 182
EN

Stack Overflow用户

发布于 2018-09-30 18:20:08

您可以简单地将此函数与save() JPAfunction一起使用,但是作为参数发送的对象必须包含数据库中现有的id,否则它将无法工作,因为当我们发送没有id的对象时,它会直接在数据库中添加一行,但是如果我们发送一个具有现有id的对象,它将更改数据库中已找到的列。

代码语言:javascript
复制
public void updateUser(Userinfos u) {
    User userFromDb = userRepository.findById(u.getid());
    // crush the variables of the object found
    userFromDb.setFirstname("john"); 
    userFromDb.setLastname("dew");
    userFromDb.setAge(16);
    userRepository.save(userFromDb);
}
票数 38
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/11881479

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档