如何防止 Spring Data JPA 中的自动更新?
How to prevent automatic update in Spring Data JPA?
在我的 Spring 启动批处理应用程序中,我从 Tasklet 调用 JPA 存储库 class。
JPA 调用从数据库中检索特定值(实体对象)。问题是,如果我更新实体对象中的某些值,一旦控件离开 Tasklet,它会自动更新到 DB,即使我没有调用任何保存操作。如何防止这种情况?默认 JPA 实现是 Hibernate。
小任务 class
Employee employee = employeeRepository.fetchEmployee(employeeName);
List<Address> addressList = employee.getAddress();
addressList.forEach(e -> e.setStatus(Status.INVALID.toString()));
存储库
@Repository
public interface EmployeeRepository extends JpaRepository<Employee, Long> {
@Query("select em from Employee em where em.employeeName = :employeeName")
public Employee fetchEmployee(@Param("employeeName") Long employeeName);
}
实体class
@Entity
@Table(name = "Employee")
public class Employee implements java.io.Serializable {
private static final long serialVersionUID = -3769636546619492649L;
private Long id;
private List<Address> address;
private String employeeName;
// Getters and setters
// @OneToMany mapping to Address
}
即使我没有调用 .save() 操作,它也会自动将地址 table 状态更新为“INVALID”
发生这种情况是因为实体未处于分离状态。在 EJB 中,我们可以通过以下方式完成此操作。
EJB解决方案
@Query(value = "select * from Employee WHERE EmployeeName = ?1", nativeQuery = true)
@TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
public List<Employee> fetchEmployee(String employeeName);
这将使交易结束。您对实体所做的更改不会保存在数据库中
Spring JPA
经过一些研究,我发现 JPA 不提供开箱即用的分离功能。
参考:https://github.com/spring-projects/spring-data-jpa/issues/641
为了让它工作,我们可以有一个覆盖分离方法的自定义 JPA 存储库。 link.
中给出了一个例子
使用深度克隆解决您的问题。
首先重写地址 class 中的克隆方法,如下所示。
注意:请通过添加您的 class attributes.Since 来自定义 clone()
方法的实现 您没有提到 class 地址的结构,我已经实现了自己的解决方案定义了 class 个属性。
地址class
public class Address {
private String country;
private String city;
private String district;
private String addressValue;
public Address() {
super();
}
public Address(String country, String city, String district, String addressValue) {
super();
this.country = country;
this.city = city;
this.district = district;
this.addressValue = addressValue;
}
//Getters and Setters
@Override
protected Object clone() {
try {
return (Address) super.clone();
} catch (CloneNotSupportedException e) {
return new Address(this.getCountry(), this.getCity(), this.getDistrict(),this.getAddressValue());
}
}
}
然后重新构造您的 class 任务集,如下所示。
任务Class
Employee employee = employeeRepository.fetchEmployee(employeeName);
List<Address> addressList = employee.getAddress();
List<Address> clonedAddressList = new ArrayList<>();
addressList.forEach(address -> clonedAddressList.add((Address)address.clone()) );
clonedAddressList.forEach(address -> address.setStatus(Status.INVALID.toString()));
在我的 Spring 启动批处理应用程序中,我从 Tasklet 调用 JPA 存储库 class。 JPA 调用从数据库中检索特定值(实体对象)。问题是,如果我更新实体对象中的某些值,一旦控件离开 Tasklet,它会自动更新到 DB,即使我没有调用任何保存操作。如何防止这种情况?默认 JPA 实现是 Hibernate。
小任务 class
Employee employee = employeeRepository.fetchEmployee(employeeName);
List<Address> addressList = employee.getAddress();
addressList.forEach(e -> e.setStatus(Status.INVALID.toString()));
存储库
@Repository
public interface EmployeeRepository extends JpaRepository<Employee, Long> {
@Query("select em from Employee em where em.employeeName = :employeeName")
public Employee fetchEmployee(@Param("employeeName") Long employeeName);
}
实体class
@Entity
@Table(name = "Employee")
public class Employee implements java.io.Serializable {
private static final long serialVersionUID = -3769636546619492649L;
private Long id;
private List<Address> address;
private String employeeName;
// Getters and setters
// @OneToMany mapping to Address
}
即使我没有调用 .save() 操作,它也会自动将地址 table 状态更新为“INVALID”
发生这种情况是因为实体未处于分离状态。在 EJB 中,我们可以通过以下方式完成此操作。
EJB解决方案
@Query(value = "select * from Employee WHERE EmployeeName = ?1", nativeQuery = true)
@TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
public List<Employee> fetchEmployee(String employeeName);
这将使交易结束。您对实体所做的更改不会保存在数据库中
Spring JPA
经过一些研究,我发现 JPA 不提供开箱即用的分离功能。
参考:https://github.com/spring-projects/spring-data-jpa/issues/641
为了让它工作,我们可以有一个覆盖分离方法的自定义 JPA 存储库。 link.
中给出了一个例子使用深度克隆解决您的问题。
首先重写地址 class 中的克隆方法,如下所示。
注意:请通过添加您的 class attributes.Since 来自定义 clone()
方法的实现 您没有提到 class 地址的结构,我已经实现了自己的解决方案定义了 class 个属性。
地址class
public class Address {
private String country;
private String city;
private String district;
private String addressValue;
public Address() {
super();
}
public Address(String country, String city, String district, String addressValue) {
super();
this.country = country;
this.city = city;
this.district = district;
this.addressValue = addressValue;
}
//Getters and Setters
@Override
protected Object clone() {
try {
return (Address) super.clone();
} catch (CloneNotSupportedException e) {
return new Address(this.getCountry(), this.getCity(), this.getDistrict(),this.getAddressValue());
}
}
}
然后重新构造您的 class 任务集,如下所示。
任务Class
Employee employee = employeeRepository.fetchEmployee(employeeName);
List<Address> addressList = employee.getAddress();
List<Address> clonedAddressList = new ArrayList<>();
addressList.forEach(address -> clonedAddressList.add((Address)address.clone()) );
clonedAddressList.forEach(address -> address.setStatus(Status.INVALID.toString()));