当前位置: 首页 > 知识库问答 >
问题:

如何使用spring数据JPA更新实体?

彭成天
2023-03-14

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

JPARepository只有一个save方法,它并不告诉我它实际上是create还是update。例如,我向数据库用户插入一个简单的对象,它有三个字段: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数据jpa和JPARepository,我如何告诉它我想要的是更新而不是插入呢?

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

共有2个答案

邴奇逸
2023-03-14

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

若要通过查询更新实体,则保存并不高效,因为它需要两个查询,而且查询可能会非常昂贵,因为它可能会连接其他表并加载任何具有FetchType=FetchType.Eage的集合

spring-data-jpa支持更新操作。
必须在存储库接口中定义方法。并用@query@modify对其进行注释。

@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用于定义自定义查询,@modify用于告诉spring-data-jpa该查询是更新操作,它需要executeUpdate()而不是executeQuery()

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

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

祁嘉木
2023-03-14

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

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

编辑:

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

>

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

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

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

  •  类似资料:
    • 问题内容: 这个问题几乎说明了一切。使用JPARepository如何更新实体? JPARepository只有一个 save 方法,它不会告诉我它是否实际上是在创建或更新。例如,我插入一个简单的对象数据库的用户,其中有三个领域:,和: 然后,我简单地调用,这实际上是数据库的插入: 到目前为止,一切都很好。现在,我想更新此用户,例如更改其年龄。为此,我可以使用QueryDSL或NamedQuery

    • 我正在尝试使用Querydsl(4.1.4)查询JPA,如本文http://www.Querydsl.com/static/Querydsl/latest/reference/html/ch02.html#jpa_integration所述。我使用Hibernate(5.2.12.final)作为JPA后端。我使用和处理器从JPA注释类生成Querydsl查询类型。 这将打印: 原始JpaUpda

    • 我正在尝试更新我的用户实体,我想到了一个错误:错误:NULL值违反了“id”列的Not NULL约束详细信息:失败的行包含(null,1,1) 这个问题肯定源于我在用户和配置文件之间的关系,即n-n

    • 我有一些实体类,其id配置如下 接下来是我的问题。例如,第一天,我获取所有记录并保存它们。但是第二天我会再次得到所有的记录,包括第一天已经保存的记录。当我试着拯救第二天的时候会发生什么?是所有记录都将再次插入还是Spring数据只插入新记录,从第一天开始的旧记录将被更新?我需要第二种情况下的行为

    • 因此,我看了关于使用Spring数据的JPA的各种教程,在许多情况下都有不同的做法,我不太确定正确的方法是什么。 假设存在follwing实体: 我们还有一个DTO,它在服务层中检索,然后交给控制器/客户端。 因此,现在假设客户想要在webui中更改他的名称--然后将会有一些控制器操作,其中将会有更新的DTO(使用旧ID和新名称)。 现在我必须将这个更新的DTO保存到数据库中。 不幸的是,目前没有