Tech/Spring

2개 이상의 DB를 사용하는 Spring Boot 환경에서 Spring Data Jpa 사용시 트랜잭션 관련 에러

소프 2023. 1. 29.

 

한 프로젝트에서 2개 이상의 DB를 연결해서 사용하기 위한 다중 DataSource 설정을 아래와 같이 했다.

 

@Configuration
@EnableTransactionManagement(proxyTargetClass = true)
@EnableJpaRepositories(
        entityManagerFactoryRef = "aJpaEntityManagerFactory",
        basePackages = {"com.soap.repository"}
)
public class ADbConfig {

    @Bean(name = "aDataSource")
    @ConfigurationProperties(prefix = "spring.a.datasource")
    public DataSource aDataSource() {
        return DataSourceBuilder.create().build();
    }

    @Bean(name = "ajpaEntityManagerFactory")
    public LocalContainerEntityManagerFactoryBean contentsEntityManagerFactory(
            EntityManagerFactoryBuilder builder
            , @Qualifier("aDataSource") DataSource dataSource
    ) {
        return builder.dataSource(dataSource).packages("com.entity.a").build();
    }

    @Bean(name = "aTransactionManager")
    public JpaTransactionManager transactionManager(
            @Qualifier("aJpaEntityManagerFactory") LocalContainerEntityManagerFactoryBean mfBean
    ) {
        JpaTransactionManager transactionManager = new JpaTransactionManager();
        transactionManager.setEntityManagerFactory(mfBean.getObject());
        return transactionManager;
    }

}

 

멀티 DB를 연결하는 프로젝트 특성상 DB 하나당 별도의 트랜잭션을 생성하도록 각각 설정 해주었다.

따라서, 특정 DB의 트랜잭션을 걸어 주기 위해, 서비스 로직에 @Transaction을 선언해줌과 동시에 속성값으로 ADbConfig에서 설정한 트랜잭션 Bean 이름("aTransactionManager")을 이름을 붙여서 선언해주었다.

그다음, Spring Data Jpa를 이용해 save() 메소드를 호출해서 저장해준다.

 

서비스

@Service
@RequiredArgsConstructor
public class FillerService {

    private final Repository repository;

    @Transactional(value = "aTransactionManager")
    public void updateSchedule(Request request) {
    	//생략..
        repository.save(request.toEntity());
    }

 

레포지토리

public interface Repository extends JpaRepository<Entity, Long> {

}

 

하지만 아래와 같은 에러가 떴으며, 발생한 지점은 repository.save() 였다.

org.springframework.beans.factory.NoSuchBeanDefinitionException: 
No bean named 'transactionManager' available: No matching TransactionManager bean found for qualifier 'transactionManager' - neither qualifier match nor bean name match!

멀티 DB를 위한 설정과 함께 별도로 트랜잭션을 만들었고, 트랜잭션 Bean 이름을 철자 하나 틀리지 않고 그대로 선언하였지만, 내가 만든 트랜잭션 이름인 'aTransactionManager'는 뜨지도 않을뿐더러, 더군다나 transacitonManager 라는 빈 이름을 찾을 수 없다고 떴다.

 

기존 코드에서 같은 DB의 다른 테이블을 바라보는 로직에 선언된 트랜잭션을 그대로 설정하였는데 안되는게 이상했다.

기존 로직은 Spring Data Jpa가 아닌 모두 QueryDsl를 사용하였고 아래와 같이 설정하고 있었다.

@Repository
public class BDataRepository extends QuerydslRepositorySupport {

    public BDataRepository() {
        super(BDataRepository.class);
    }

    @Override
    @PersistenceContext(unitName = "aJpaEntityManagerFactory")
    public void setEntityManager(EntityManager entityManager) {
        super.setEntityManager(entityManager);
        this.queryFactory = new JPAQueryFactory(entityManager);
    }
	
    //생략...
}

 

여기서 힌트를 얻어 Data Jpa를 사용해서 문제인걸로 추측을 했고

Config 설정을 다시 확인해보았더니, transactionManagerRef 속성을 지정하지 않고 있었다.

 

EnableJpaRepositories에서 transactionManagerRef 라는 속성을 볼 수 있다. 기본적으로 Spring Data Jpa는 TransactionManager를 제공해주고 그 transactionManager에 대한 default bean 이름이 transactionManager로 되어있다. 

그래서 만약 transactionManagerRef를 지정하지 않는 상태에서 PlatformTransactionManager bean 이름을 transactionManager로 설정하면 등록이 되지만, 다른 이름으로 변경한 상태에서 application을 실행하면 "transactionManager" 이름을 찾을 수 없다는 에러가 발생한다.

@EnableJpaRepositories 자체가 Spring Data Jpa를 활성화하기 위한 어노테이션이였다.

 

아래와 같이 transactionManagerRef 속성을 추가해주었더니 더이상 에러가 뜨지 않았다.

@Configuration
@EnableTransactionManagement(proxyTargetClass = true)
@EnableJpaRepositories(
        entityManagerFactoryRef = "aJpaEntityManagerFactory",
        transactionManagerRef = "aTransactionManager",
        basePackages = {"com.soap.repository"}
)
public class ADbConfig {

    //생략..

    @Bean(name = "aTransactionManager")
    public JpaTransactionManager transactionManager(
            @Qualifier("aJpaEntityManagerFactory") LocalContainerEntityManagerFactoryBean mfBean
    ) {
        JpaTransactionManager transactionManager = new JpaTransactionManager();
        transactionManager.setEntityManagerFactory(mfBean.getObject());
        return transactionManager;
    }

}

 

 

참고

 

https://doridorigang.tistory.com/10

 

Java 기반 Spring설정(2) - JPA

1편에서는 간단한 RootApplicationContext와 WebApplicationContext를 설정하였다면, JPA 설정기반과 Transaction 설정 위주로 진행하겠다. 1. JdbcTemplate Transaction 설정 지난 포스터에서는 Transaction 설정이 빠져있어

doridorigang.tistory.com

 

 

 

댓글