Spring JpaRepository - 엔티티 분리 및 부착
나는 봄 부츠를 사용하고 있고 jpa 위에서 동면을 하고 있습니다.저는 JpaRepository 인터페이스를 사용하여 저장소를 구현하고 있습니다.다음 UserRepository와 동일함
public interface UserRepository extends JpaRepository<User, Long> {
}
나는 다음을 이루고 싶습니다.
- User 엔티티를 로드합니다.
- 개체의 상태(예: 사용자)를 변경합니다.setName("foo")
- 외부 시스템 웹 서비스 호출을 수행합니다.통화결과를 DB에 저장
- 이 웹 서비스 호출에 대한 응답이 성공한 경우에만 새 사용자 상태를 리포지토리에 저장합니다.
위의 모든 단계는 하나의 트랜잭션에서 발생하지 않습니다. 즉, 외부 서비스 호출이 트랜잭션을 벗어났습니다.
저장소를 통해 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의 답변은 정확하고 효과적이지만, 모든 저장소 인터페이스에 이러한 기능을 추가하고자 할 때 유연성이 부족하다는 것을 알게 되었습니다. 따라서 사용자 지정 저장소 공장에서 다음과 같은 접근 방식을 사용하고 있습니다.
- 분리 기능을 위한 중간 인터페이스 만들기:
@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);
}
- 중간 인터페이스의 구현을 만듭니다.
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);
}
}
- 사용자 지정 리포지토리 공장을 만듭니다.
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;
}
}
- 위에서 만든 공장의 사용을 선언하기 위해 사용자 지정 저장소 공장 빈을 만듭니다.
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);
}
}
- 사용자 정의 공장을 스프링 구성으로 선언합니다.
@EnableJpaRepositories(repositoryFactoryBeanClass = DetachableJpaRepositoryFactoryBean.class)
public class MyApplication {...}
- 이제 저장소에서 새로운 중간 인터페이스를 사용할 수 있습니다.
@Repository
public interface UserRepository extends DetachableJpaRepository<User, Long> {
}
- 그리고.
detach
method는 다음 저장소에서 사용할 수 있습니다.
@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
'source' 카테고리의 다른 글
WooCommerce - 카트에 있는 제품에 대해 선택된 변형을(를) (0) | 2023.10.19 |
---|---|
대용량 파일을 삽입할 때 "ORA-03135: 연결 끊김" (0) | 2023.10.19 |
상위 노드 없이 모든 하위 노드(요소, 주석, 텍스트)를 가져오는 XPath (0) | 2023.10.19 |
Xcode 6.1/Swift로 프로그래밍 방식으로 이미지를 UImageView로 설정 (0) | 2023.10.19 |
HTML에서 wrap text를 어떻게 말합니까? (0) | 2023.10.19 |