codememo

스프링 컨테이너 외부에서 스프링 데이터 JPA를 사용하는 방법은 무엇입니까?

tipmemo 2023. 8. 31. 23:54
반응형

스프링 컨테이너 외부에서 스프링 데이터 JPA를 사용하는 방법은 무엇입니까?

Springbean 컨테이너를 사용하지 않고 DAO 프록시(일명 Repository)를 생성할 수 있도록 Spring Data JPA 개체를 수동으로 연결하려고 합니다.

필연적으로, 나는 왜 이것을 하고 싶은지 물어볼 것입니다: 그것은 우리의 프로젝트가 이미 Google Guice(그리고 GWT와 함께 Gin을 사용하는 UI)를 사용하고 있고, 우리는 다른 IoC 컨테이너 구성을 유지하거나 그로 인한 모든 종속성을 끌어들이고 싶지 않기 때문입니다.우리가 귀스를 사용할 수 있을지도 모른다는 것을 압니다.SpringIntegration하지만 이것이 최후의 수단이 될 것입니다.

물건을 수동으로 연결할 수 있는 모든 것이 가능한 것처럼 보이지만, 문서화가 잘 되지 않아 어려움을 겪고 있습니다.

Spring Data 사용자 가이드에 따르면 저장소 팩토리를 독립적으로 사용할 수 있습니다.불행하게도, 그 예는 보여줍니다.RepositoryFactorySupport추상적인 수업입니다.몇 가지 검색을 한 후에 나는 간신히 찾을 수 있었습니다.

JpaRepositoryFactory트랜잭션이 자동으로 생성되지 않는 경우를 제외하고는 실제로 상당히 잘 작동합니다.트랜잭션을 수동으로 관리해야 합니다. 그렇지 않으면 데이터베이스에 유지되는 작업이 없습니다.

entityManager.getTransaction().begin();
repositoryInstance.save(someJpaObject);
entityManager.getTransaction().commit();

문제는 그것으로 밝혀졌습니다.@Transactional주석은 자동으로 사용되지 않으며, 사용자의 도움이 필요합니다.TransactionInterceptor

감사하게도.JpaRepositoryFactory콜백을 수행하여 다음을 반환하기 전에 생성된 리포지토리 프록시에 AOP 조언을 추가할 수 있습니다.

final JpaTransactionManager xactManager = new JpaTransactionManager(emf);
final JpaRepositoryFactory factory = new JpaRepositoryFactory(emf.createEntityManager());

factory.addRepositoryProxyPostProcessor(new RepositoryProxyPostProcessor() {
    @Override
    public void postProcess(ProxyFactory factory) {
        factory.addAdvice(new TransactionInterceptor(xactManager, new AnnotationTransactionAttributeSource()));
    }
});

여기가 일이 잘 풀리지 않는 곳입니다.코드에서 디버거를 밟는 것은,TransactionInterceptor실제로 거래를 만들고 있습니다 - 하지만 잘못된 것입니다.EntityManager스프링이 활성화 상태를 관리합니다.EntityManager현재 실행 중인 스레드를 보면.TransactionInterceptor이렇게 하면 활성화되지 않음을 알 수 있습니다.EntityManager스레드에 바인딩되고 새 스레드를 만들기로 결정합니다.

하지만, 이 새로운 것은EntityManager생성되어 에 전달된 것과 동일한 인스턴스가 아닙니다.JpaRepositoryFactory생성자, 이것은 필요합니다.EntityManager문제는 내가 어떻게 만들 것인가 하는 것입니다.TransactionInterceptor그리고JpaRepositoryFactory같은 것을 사용합니다.EntityManager?

업데이트:

이 글을 쓰면서 문제를 해결하는 방법을 찾았지만 여전히 이상적인 해결책은 아닐 수 있습니다.저는 이 솔루션을 별도의 답변으로 게시하겠습니다.Spring Data JPA를 해결하는 방법보다 독립 실행형으로 사용하는 더 나은 방법에 대한 제안을 듣게 되어 기쁩니다.

『 』 『 』 『 』의 JpaRepositoryFactory Spring 그고그따스프통합링른에리▁and통합▁the.JpaRepositoryFactory콩은 다음과 같습니다.

관리되는 JPA 런타임 환경 내에서 애플리케이션을 실행할 수 있으며, 어떤 환경이든 상관없다고 가정합니다.

이 가 주사에 EntityManager금도보다 .EntityManagerFactory정의에 따르면EntityManager스레드 세이프가 아닙니다.그래서 만약 처리된다면,EntityManagerFactory직접적으로 관리되는 런타임 환경(Spring 또는 EJB)이 제공하는 모든 리소스 관리 코드를 다시 작성해야 합니다.

Spring Spring's Spring을 합니다.SharedEntityManagerCreator수동으로 구현한 트랜잭션 리소스 바인딩 마법을 실제로 수행합니다.그래서 당신은 아마도 그것을 사용하여 당신을 만들기를 원할 것입니다.EntityManager의 의턴스의 EntityManagerFactory저장소 빈에서 트랜잭션 기능을 직접 활성화하려는 경우(예: e.g.에 대한 호출).repo.save(…) 활성화되어 ). 를 합니다.TransactionalRepositoryProxyPostProcessorSpring Data Commons는 다음과 같습니다. Data 때합니다(예: Spring Data의 경우).repo.save(…)) 및 정의하여 구현 하여 리포지토리 인터페이스가 인트랜구 정를스선에 된 트랜잭션 할 수 있도록 SimpleJpaRepository.

수동으로 바인딩하여 해결했습니다.EntityManager그리고.EntityManagerFactory실행 중인 스레드로, 저장소를 생성하기 전에 만들기 전에JpaRepositoryFactory은 이작은다수행다니됩사여용하를 하여 수행됩니다.TransactionSynchronizationManager.bindResource방법:

emf = Persistence.createEntityManagerFactory("com.foo.model", properties);
em = emf.createEntityManager();

// Create your transaction manager and RespositoryFactory
final JpaTransactionManager xactManager = new JpaTransactionManager(emf);
final JpaRepositoryFactory factory = new JpaRepositoryFactory(em);

// Make sure calls to the repository instance are intercepted for annotated transactions
factory.addRepositoryProxyPostProcessor(new RepositoryProxyPostProcessor() {
    @Override
    public void postProcess(ProxyFactory factory) {
        factory.addAdvice(new TransactionInterceptor(xactManager, new MatchAlwaysTransactionAttributeSource()));
    }
});

// Create your repository proxy instance
FooRepository repository = factory.getRepository(FooRepository.class);

// Bind the same EntityManger used to create the Repository to the thread
TransactionSynchronizationManager.bindResource(emf, new EntityManagerHolder(em));

try{
    repository.save(someInstance); // Done in a transaction using 1 EntityManger
} finally {
    // Make sure to unbind when done with the repository instance
    TransactionSynchronizationManager.unbindResource(getEntityManagerFactory());
}

그래도 더 좋은 방법이 있을 겁니다.가 Repository Factory를 .EnitiyManager신에대 EntityManagerFactory나는 예상한다, 그것이 먼저 볼 것이라고.EntityManger스레드에 바인딩된 다음 새 스레드를 생성하여 바인딩하거나 기존 스레드를 사용합니다.

기본적으로 저장소 프록시를 주입하고 모든 호출에서 내부적으로 새 프록시를 생성합니다.EntityManager통화가 스레드 세이프가 되도록 합니다.

언급URL : https://stackoverflow.com/questions/9123964/how-do-you-use-spring-data-jpa-outside-of-a-spring-container

반응형