简体   繁体   English

如何防止 Spring 数据 JPA 中的自动更新?

[英]How to prevent automatic update in Spring Data JPA?

In my Spring boot batch application, I am calling a JPA repository class from Tasklet.在我的 Spring 启动批处理应用程序中,我从 Tasklet 调用 JPA 存储库 class。 The JPA call retrieves a particular value (Entity object) from DB. JPA 调用从 DB 中检索特定值(实体对象)。 The problem is, If I update some value in the entity object, once the control goes out of Tasklet, it automatically updates to DB even though I am not calling any save operation.问题是,如果我更新实体 object 中的某些值,一旦控件退出 Tasklet,即使我没有调用任何保存操作,它也会自动更新到 DB。 How to prevent this?如何防止这种情况? Default JPA implementation is Hibernate.默认 JPA 实现是 Hibernate。

Tasklet class小任务 class

Employee employee = employeeRepository.fetchEmployee(employeeName);
List<Address> addressList = employee.getAddress();
addressList.forEach(e -> e.setStatus(Status.INVALID.toString()));

Repository存储库

@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);
}

Entity class实体 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
}

Even though I am not calling a.save() operation, it automatically updates Address table Status to "INVALID"即使我没有调用 a.save() 操作,它也会自动将地址表状态更新为“无效”

This happen because the entity is not in detached state.发生这种情况是因为实体不在分离的 state 中。 In EJB we can do this in the following way.在 EJB 中,我们可以通过以下方式做到这一点。

EJB solution EJB 解决方案

@Query(value = "select * from Employee WHERE EmployeeName = ?1", nativeQuery = true)
@TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
public List<Employee> fetchEmployee(String employeeName);

This will make the transaction closed.这将使交易关闭。 Changes you make to entity will not get saved in DB您对实体所做的更改不会保存在数据库中

Spring JPA Spring JPA

After a bit of research i found JPA doesn't provide the detach functionality out of the box.经过一番研究,我发现 JPA 不提供开箱即用的分离功能。

Refer: https://github.com/spring-projects/spring-data-jpa/issues/641参考: https://github.com/spring-projects/spring-data-jpa/issues/641

To make it work we can have a custom JPA repository which overrides detach method.为了让它工作,我们可以有一个自定义的 JPA 存储库,它会覆盖分离方法。 An example is given in this link.此链接中给出了一个示例。

https://www.javaer101.com/en/article/1428895.html https://www.javaer101.com/en/article/1428895.html

Use Deep cloning to solve your issue.使用深度克隆来解决您的问题。

First override the clone method inside your Address class like below.首先覆盖地址 class 中的克隆方法,如下所示。 Note: Please customize the implementation of clone() method by adding your class attributes.Since you didn't mention the structure of the class Address, I have implemented the solution with my own defined class attributes.注意:请通过添加您的 class 属性来自定义clone()方法的实现。由于您没有提到 class 地址的结构,我已经使用自己定义的 class 属性实现了该解决方案。

Address 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());
        }
    }

}

Then re construct your class Tasket like below.然后重新构建您的 class Tasket,如下所示。

Tasket 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()));

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM