Spring JpaRepository - Detach and Attach entity

2022-09-01 02:25:49

我正在使用弹簧靴并在jpa上休眠。我正在使用JpaRepository接口来实现我的存储库。与以下用户存储库一样

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

我想实现以下目标

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

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

当我通过其存储库将 Web 服务结果保存到 DB 中时,我在 User 实体中的更改也会被保存。根据我的理解,这是由于在步骤#3中底层的持久性上下文的冲洗。经过一些谷歌,我认为我可以实现我的目的,如果我可以在步骤一中分离我的用户实体,并在步骤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
}

谢谢


答案 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);
    }
    ...
}

我还没有尝试过这个代码,但你应该能够让它工作。您甚至可以尝试在服务类(where is)中保留 ,并避免将自定义实现添加到存储库的喧嚣。EntityManagerupdateUser()@PersistenceContext


答案 2

entityManager.clear()将断开所有 JPA 对象的连接,因此,如果您计划保持连接的其他对象,则可能不是所有情况下的合适解决方案。

清楚

/**
 * Clear the persistence context, causing all managed
 * entities to become detached. Changes made to entities that
 * have not been flushed to the database will not be
 * persisted.
 */
public void clear();

entityManager.detach(entity);从持久性上下文中移除给定实体

分离

/**
 * Remove the given entity from the persistence context, causing
 * a managed entity to become detached.  Unflushed changes made
 * to the entity if any (including removal of the entity),
 * will not be synchronized to the database.  Entities which
 * previously referenced the detached entity will continue to
 * reference it.
 * @param entity  entity instance
 * @throws IllegalArgumentException if the instance is not an
 *         entity
 * @since Java Persistence 2.0
 */
public void detach(Object entity);

推荐