Spring JpaRepository - 分离和附加实体

时间:2014-11-07 06:31:09

标签: java spring hibernate jpa spring-data-jpa

我正在使用spring boot并在jpa上休眠。我正在使用JpaRepository接口来实现我的存储库。与以下UserRepository一样

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

我想实现以下

  1. 加载用户实体。
  2. 更改实体对象的状态,例如user.setName(&#34;富&#34)
  3. 执行外部系统Web服务调用。将通话结果保存在DB
  4. 仅在成功响应此Web服务调用时,将新用户状态保存在存储库中。
  5. 上述所有步骤都不会发生在一个事务中,即外部服务调用不在事务中。

    当我通过其存储库将我的web服务结果保存在DB中时,我的用户实体更改也会保存。根据我的理解,这是由于在步骤#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
    }
    

    由于

3 个答案:

答案 0 :(得分:43)

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

由于JpaRepository本身并不提供此功能,您可add a custom implementation向它提供此类内容

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,并避免将自定义实现添加到存储库。

答案 1 :(得分:4)

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

答案 2 :(得分:0)

按照@Predrag Maric 的建议使用自定义实现显然是这个问题的正确答案。但是,我发现在服务层执行分离要好得多,因为它通常知道实体是否应该分离。

只需将其与服务中的 @PersistenceContext 连接即可。

@Service
class ConsumerServiceImpl {

    @PersistenceContext
    private EntityManager entityManager
...

    entityManager.detach(en)