source

Spring JpaRepository - 엔티티 분리 및 부착

ittop 2023. 10. 19. 22:44
반응형

Spring JpaRepository - 엔티티 분리 및 부착

나는 봄 부츠를 사용하고 있고 jpa 위에서 동면을 하고 있습니다.저는 JpaRepository 인터페이스를 사용하여 저장소를 구현하고 있습니다.다음 UserRepository와 동일함

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

나는 다음을 이루고 싶습니다.

  1. User 엔티티를 로드합니다.
  2. 개체의 상태(예: 사용자)를 변경합니다.setName("foo")
  3. 외부 시스템 웹 서비스 호출을 수행합니다.통화결과를 DB에 저장
  4. 이 웹 서비스 호출에 대한 응답이 성공한 경우에만 새 사용자 상태를 리포지토리에 저장합니다.

위의 모든 단계는 하나의 트랜잭션에서 발생하지 않습니다. 즉, 외부 서비스 호출이 트랜잭션을 벗어났습니다.

저장소를 통해 DB에 웹 서비스 결과를 저장하면 User Entity의 변경 내용도 저장됩니다.제가 알기로는 3단계에서 언더레이잉 지속성 컨텍스트가 플러시되기 때문인 것 같습니다. 구글을 좀 한 후에 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
}

감사해요.

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()is) 와@PersistenceContext, 저장소에 사용자 정의 구현을 추가해야 하는 번거로움을 피할 수 있습니다.

@Predrag Maric이 제안하는 대로 맞춤형 구현을 사용하는 것이 이 질문에 대한 올바른 대답입니다.그러나 서비스 계층에서 분리를 수행하는 것이 개체를 분리해야 하는지 여부를 평소에 알고 있기 때문에 훨씬 더 낫다는 것을 알게 되었습니다.

그냥 연결해주세요.@PersistenceContext취역 중인

@Service
class ConsumerServiceImpl {

    @PersistenceContext
    private EntityManager entityManager
...

    entityManager.detach(en)

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

Predrag Maric의 답변은 정확하고 효과적이지만, 모든 저장소 인터페이스에 이러한 기능을 추가하고자 할 때 유연성이 부족하다는 것을 알게 되었습니다. 따라서 사용자 지정 저장소 공장에서 다음과 같은 접근 방식을 사용하고 있습니다.

  1. 분리 기능을 위한 중간 인터페이스 만들기:
@NoRepositoryBean // this annotation is important here if the package you are putting this interface in is scanned for repositories (is in basePackage)
public interface DetachableJpaRepository<T, TID> extends JpaRepository<T, TID> { // you can also extend other repositories here, like JpaSpecificationExecutor
    void detach(T entity);
}
  1. 중간 인터페이스의 구현을 만듭니다.
public class DetachableJpaRepositoryImpl<T, TID> extends SimpleJpaRepository<T, TID> implements DetachableJpaRepository<T, TID> {
    private final EntityManager entityManager;

    public DetachableJpaRepositoryImpl(Class<T> domainClass, EntityManager entityManager) {
        super(domainClass, entityManager);
        this.entityManager = entityManager;
    }

    @Override
    public void detach(T entity) {
        entityManager.detach(entity);
    }
}
  1. 사용자 지정 리포지토리 공장을 만듭니다.
public class DetachableJpaRepositoryFactory<T, TID> extends JpaRepositoryFactory {
    public DetachableJpaRepositoryFactory(EntityManager entityManager) {
        super(entityManager);
    }

    @Override
    protected JpaRepositoryImplementation<?, ?> getTargetRepository(RepositoryInformation information, EntityManager entityManager) {
        return new DetachableJpaRepositoryImpl<T, TID>((Class<T>) information.getDomainType(), entityManager);
    }

    @Override
    protected Class<?> getRepositoryBaseClass(RepositoryMetadata metadata) {
        return DetachableJpaRepository.class;
    }
}
  1. 위에서 만든 공장의 사용을 선언하기 위해 사용자 지정 저장소 공장 빈을 만듭니다.
public class DetachableJpaRepositoryFactoryBean<R extends JpaRepositoryImplementation<T, TID>, T, TID> extends JpaRepositoryFactoryBean<R, T, TID> {
    public DetachableJpaRepositoryFactoryBean(Class<? extends R> repositoryInterface) {
        super(repositoryInterface);
    }

    @Override
    protected RepositoryFactorySupport createRepositoryFactory(EntityManager entityManager) {
        return new DetachableJpaRepositoryFactory<T, TID>(entityManager);
    }
}
  1. 사용자 정의 공장을 스프링 구성으로 선언합니다.
@EnableJpaRepositories(repositoryFactoryBeanClass = DetachableJpaRepositoryFactoryBean.class)
public class MyApplication {...}
  1. 이제 저장소에서 새로운 중간 인터페이스를 사용할 수 있습니다.
@Repository
public interface UserRepository extends DetachableJpaRepository<User, Long> {
}
  1. 그리고.detachmethod는 다음 저장소에서 사용할 수 있습니다.
@Autowired
private UserRepository userRepository;
...
userRepository.detach(user);

사용자 지정 저장소에 다른 기능을 추가할 수 있을 뿐만 아니라 이 접근 방식이 매우 유연하다는 것을 알게 되었습니다.

또한 나는 Chayne P.S.의 답변에 동의하지 않습니다. imo 당신은 서비스 계층에서 엔티티 관리자를 사용해서는 안 됩니다. 이것은 엔티티 상태를 관리하는 dao 계층 책임입니다. Chayne P.S가 제안하는 것은 나쁜 디자인입니다. imo, 서비스 계층은 엔티티 관리자를 인식해서는 안 됩니다.

언급URL : https://stackoverflow.com/questions/26795436/spring-jparepository-detach-and-attach-entity

반응형