【问题标题】:Spring JpaRepository - Detach and Attach entitySpring JpaRepository - 分离和附加实体
【发布时间】:2015-01-03 21:38:51
【问题描述】:

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

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

我想实现以下目标

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

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

当我通过其存储库将我的 Web 服务结果保存到 DB 中时,我在用户实体中的更改也会被保存。根据我的理解,这是由于在第 3 步刷新了底层持久性上下文。经过一番 google,我认为我可以实现我的目的,如果我可以在第 1 步分离我的用户实体并在第 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 到 4 发布您当前的代码(以澄清)
  • 是否可以按以下顺序拨打电话:1,3,4,2?

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


【解决方案1】:

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

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

@Service
class ConsumerServiceImpl {

    @PersistenceContext
    private EntityManager entityManager
...

    entityManager.detach(en)

【讨论】:

    【解决方案2】:

    如果您使用的是 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);
        }
        ...
    }
    

    我没有尝试过这段代码,但你应该可以让它工作。您甚至可以尝试使用@PersistenceContext 在您的服务类(updateUser() 所在的位置)中保留EntityManager,并避免向存储库添加自定义实现的麻烦。

    【讨论】:

    • 谢谢,这种方法在我的 Spring Boot 应用程序中有效。 (冒昧地将@Repository 添加到示例代码中的实现中;否则自定义存储库无法自动装配。)
    • CrudRepository 可以使用相同的方法吗?
    • @DBS 没试过,应该是一样的
    【解决方案3】:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-09-11
      • 2016-06-25
      • 1970-01-01
      • 2016-03-16
      • 1970-01-01
      • 1970-01-01
      • 2010-09-28
      相关资源
      最近更新 更多