Java 每次使用JPA持久化相同的对象时,都会在数据库中插入一个新行
使用Java 每次使用JPA持久化相同的对象时,都会在数据库中插入一个新行,java,spring-boot,jpa,spring-data-jpa,Java,Spring Boot,Jpa,Spring Data Jpa,使用javax.persistence.*annotations注释此类: @Entity public class Car{ @Id @GeneratedValue(strategy = GenerationType.AUTO) private Integer id; private Integer weight; public setWeight(weight) { this.weight = weight }
javax.persistence.*
annotations注释此类:
@Entity
public class Car{
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
private Integer weight;
public setWeight(weight) {
this.weight = weight
}
public Integer getWeight() {
return this.weight;
}
}
当使用SpringJpaRepository
interfacesave(S entity)
方法将此类的对象X保存在数据库中时,它将生成此对象的Id并保存在数据库中
但是,如果对象X状态发生更改,并使用save(S entity)
方法再次保存,则不会更新数据库中的旧行,而是创建新行。我猜这种行为是因为在自动生成第一条保存消息返回后,对象id没有被更新(看起来需要一个刷新操作)
所以这是行不通的:
Car myCar = new Car();
carJPARepository.save(myCar); --> New row in Database is inserted;
myCar.setWeight(Integer.valueOf(1000));
carJPARepository.save(myCar); --> New row is inserted in Database instead updated the first one
顺便说一下,save(S entity)
方法的文档说明:
保存给定的实体。将返回的实例用于进一步的操作,因为保存操作可能已经完全更改了实体实例
这是否意味着我们作为参数传递给save方法的对象与它返回的对象不同,可能具有不同的状态?Car myCar=new Car();
myCar=carJPARepository.save(myCar);//获取具有更新id的汽车对象
myCar.设定重量(整数值为(1000));
carJPARepository.save(我的车);//调用save现在将更新为java对象作为id
您好,请按照我的示例简单了解流程。
在save
之前,该实例不受管理,之后则不受管理。因此,对实体所做的所有更改都符合更新操作的条件
点击dirty save
端点时,您应该会看到类似于以下内容的日志:
Object before save is not assigned default id value and weight is anyway null
Car(id=null, weight=null)
Hibernate: values next value for hibernate_sequence
Hibernate: insert into car (weight, id) values (?, ?)
Plain saved object with default value
Car(id=1, weight=null)
Hibernate: update car set weight=? where id=?
Object with updated weight field
Car(id=1, weight=1000)
如您所见,当您将权重设置为1000时,考虑更新而不是创建新记录。
package com.example.demo;
进口龙目吸气剂;
进口龙目织机;
进口龙目草;
导入org.springframework.beans.factory.annotation.Autowired;
导入org.springframework.data.jpa.repository.JpaRepository;
导入org.springframework.stereotype.Repository;
导入org.springframework.stereotype.Service;
导入org.springframework.transaction.annotation.Transactional;
导入org.springframework.web.bind.annotation.*;
导入javax.persistence.Entity;
导入javax.persistence.GeneratedValue;
导入javax.persistence.GenerationType;
导入javax.persistence.Id;
@RestController
@请求映射(“/cars”)
公共类汽车控制器{
私人终审车服务;
@自动连线
公共车辆控制员(车辆服务){
this.carService=carService;
}
@GetMapping
公共可出租汽车{
返回carService.cars();
}
@邮戳
公共车辆创建(@RequestBody Car){
返回汽车服务。保存(汽车);
}
@后期映射(路径=“脏保存”)
公共汽车dirtyCreate(){
我的车=新车();
System.out.println(“保存前的对象未指定默认id值,且权重为空”);
系统输出打印项次(myCar);
carService.save(myCar);
System.out.println(“带默认值的普通保存对象”);
系统输出打印项次(myCar);
myCar.设定重量(1000);
carService.save(myCar);
System.out.println(“具有更新权重字段的对象”);
系统输出打印项次(myCar);
归还我的车;
}
}
@吸气剂
@塞特
@托斯特林
@实体
班车{
@身份证
@GeneratedValue(策略=GenerationType.AUTO)
私有整数id;
私有整数权重;
}
@服务
等级车服务{
私人最终转帐转帐;
@自动连线
carreservice(CarRepository CarRepository){
this.carRepository=carRepository;
}
@交易的
公共汽车拯救(汽车){
返回存储。保存(汽车);
}
@事务(只读=真)
公共可出租汽车{
return carRepository.findAll();
}
}
@存储库
接口存储扩展了JPA存储{
}
将save
方法的返回值分配给myCar
,以获取托管实例。您可能是在非事务性测试方法中运行此测试,从而导致分离实例,而不是重用持久实例。您是否可以发布控制器和服务代码?@M.Deinum,这在使用JPA存储库时是不必要的;正确的解决方案是修复事务性。我已使用JPARepository和org.springframework.transaction.annotation.Transactional annotation对该类进行了注释,但在保存消息返回后,该对象的id仍然为0。。但是save方法返回的对象是另一个对象(这个对象具有正确的id集)。如果我没有记错的话,persist、update、find和delete是JPA的autogen方法。如果save()方法调用persist(),则每次都会创建一个新行,除非有某种逻辑检查实体中的ID=null并调用update(id),当执行(在同一方法体中):Car myCar=new Car()时,它不工作;carJPARepository.save(myCar);myCar.setWeight(1000);-->在这里,myCar仍然没有新的id设置。通常,使您的@Controller
`@具有事务性是个坏主意,服务层应该是事务边界,而不是web层。