一尘不染

Spring JpaRepository-分离并附加实体

hibernate

我正在使用Spring Boot并通过jpahibernate。我正在使用JpaRepository接口来实现我的存储库。与以下UserRepository一样

public interface UserRepository extends JpaRepository<User, Long> {
}

我想实现以下目标

  1. 加载用户实体。
  2. 更改实体对象的状态,例如user.setName(“ foo”)
  3. 进行外部系统Web服务调用。将通话结果保存到数据库中
  4. 仅在成功响应此Web服务调用后,才将用户的新状态保存在存储库中。

以上所有步骤都不会在一个事务中发生,即外部服务调用已结束事务。

当我通过Web服务的存储库将Webservice结果保存到DB中时,我对User实体的更改也将保存。根据我的理解,这是由于在步骤#3中清除了持久性上下文的原因。经过一番google之后,如果我可以在第一步中分离用户实体并在步骤4中重新附加用户实体,我想我就可以达到目的。请确认如果我的理解是正确的,我将如何实现?JpaRepository接口中没有分离实体的方法。

以下是说明代码

public void updateUser(int id, String name, int changeReqId){
    User mUser = userRepository.findOne(id); //1
    mUser.setName(name); //2

    ChangeRequest cr = changeRequestRepository.findOne(changeReqId);
    ChangeResponse rs = userWebService.updateDetails(mUser); //3

    if(rs.isAccepted()){
        userRepository.saveAndFlush(mUser); //4
    }

    cr.setResponseCode(rs.getCode());
    changeRequestRepository.saveAndFlush(cr); //this call also saves the changes at step 2
}

谢谢


阅读 240

收藏
2020-06-20

共1个答案

一尘不染

如果使用的是JPA
2.0,则可以使用EntityManager#detach()从持久性上下文中分离单个实体。另外,Hibernate具有一个Session#evict(),它具有相同的作用。

由于JpaRepository本身不提供此功能,因此您可以向其添加自定义实现,如下所示

public interface UserRepositoryCustom {
    ...
   void detachUser(User u);
    ...
}

public interface UserRepository extends JpaRepository<User, Long>, UserRepositoryCustom {
    ...
}

@Repository
public class UserRepositoryCustomImpl implements UserRepositoryCustom {
    ...
    @PersistenceContext
    private EntityManager entityManager;

    @Override
    public void detachUser(User u) {
        entityManager.detach(u);
    }
    ...
}

我没有尝试过此代码,但是您应该可以使其工作。您甚至可以尝试通过保留EntityManager服务类(在哪里updateUser()@PersistenceContext,并避免将自定义实现添加到存储库的麻烦。

2020-06-20