Spring JpaRepository - 分离和附加实体

ami*_*que 22 java spring hibernate jpa spring-data-jpa

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

public interface UserRepository extends JpaRepository<User, Long> {
}
Run Code Online (Sandbox Code Playgroud)

我想实现以下目标

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

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

当我通过其存储库将我的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
}
Run Code Online (Sandbox Code Playgroud)

谢谢

Pre*_*ric 47

如果您使用的是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);
    }
    ...
}
Run Code Online (Sandbox Code Playgroud)

我没有尝试过这段代码,但你应该能够使它运行起来.您甚至可以尝试EntityManager在服务类(where where updateUser())中保留@PersistenceContext,并避免将自定义实现添加到存储库的喧嚣.

  • 春天4对我不起作用. (3认同)

Cha*_* S. 13

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

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

@Service
class ConsumerServiceImpl {

    @PersistenceContext
    private EntityManager entityManager
...

    entityManager.detach(en)

Run Code Online (Sandbox Code Playgroud)


Xst*_*ian 5

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();
Run Code Online (Sandbox Code Playgroud)

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);
Run Code Online (Sandbox Code Playgroud)