728x90
반응형
문제

프로젝트에서 MySQL(JPA)과 MongoDB를 함께 사용하는데
MongoDB를 사용한 테스트 중 테스트는 잘 되지만 롤백이 안되는 현상을 겪었다
@Configuration
public class MongoConfig {
@Bean
MongoTransactionManager mongoTransactionManager(MongoDatabaseFactory dbFactory) {
return new MongoTransactionManager(dbFactory);
}
}
그래서 찾아보니 MongoDB의 롤백을 위해 MongoTransactionManager를 빈으로 등록해서
MongoDB도 트랜잭션을 사용하니 테스트시 롤백이 잘 되었다
그런데, 이번엔 잘 돌아가던 JPA 기반의 회원 테스트들이 줄줄이 실패하는 현상이 발생했다
728x90
원인: 트랜잭션 매니저의 중복
Spring은 @Transactional 어노테이션을 만나면 빈 컨테이너에서 PlatformTransactionManager 타입의 빈을 찾는다
- JPA만 쓸 때: 스프링 부트가 JpaTransactionManager를 자동으로 등록하고 이를 기본으로 사용
- MongoDB 매니저 추가 후: 컨테이너에 JpaTransactionManager와 MongoTransactionManager 두 개가 공존하게 됨
이때 별도의 설정을 하지 않으면 스프링은 어떤 매니저를 기본으로 써야 할지 몰라 엉뚱한 매니저를 선택하거나 에러를 발생시킨다
JPA 로직에 MongoDB용 매니저가 투입되면 당연히 MySQL 롤백은 실패
반응형
해결 방법: 명확한 이름 부여와 @Primary 설정
어떤 녀석이 기본인지 정해주고, 특수한 상황(MongoDB)에서만 이름을 불러주는 것
1. TransactionConfig 설정
@Configuration
public class TransactionConfig {
// JPA 트랜잭션 매니저를 '기본'으로 설정
@Primary
@Bean(name = "transactionManager")
public PlatformTransactionManager jpaTransactionManager(EntityManagerFactory entityManagerFactory) {
return new JpaTransactionManager(entityManagerFactory);
}
// MongoDB용 트랜잭션 매니저는 별도의 이름을 부여
@Bean(name = "mongoTransactionManager")
public MongoTransactionManager mongoTransactionManager(MongoDatabaseFactory dbFactory) {
return new MongoTransactionManager(dbFactory);
}
}
MongoTransactionManager에 이름을 부여하고, 기존 JPA 매니저를 @Primary로 설정
2. 서비스 코드에서 구분해서 사용
이제 @Transactional만 쓰면 JPA 매니저가 작동하고, 몽고디비용은 이름을 명시
- JPA 서비스 (회원 가입 등):
@Transactional // @Primary인 jpaTransactionManager가 자동으로 선택됨 public void registerMember() { ... } - MongoDB 서비스 (로그, 프롬프트 저장 등):
@Transactional(value = "mongoTransactionManager") // 명시적으로 지정 public void savePrompt() { ... }
3. 테스트 코드 작성 시 주의사항
// 1. JPA 테스트 (MySQL 롤백 필요 시)
@SpringBootTest
@Transactional
class MemberServiceTest { ... }
// 2. MongoDB 테스트 (Atlas 롤백 확인 시)
@SpringBootTest
@Transactional("mongoTransactionManager")
class PromptServiceTest { ... }
테스트 환경에서도 적용
참고: MongoDB 트랜잭션을 테스트하려면 사용 중인 MongoDB가 반드시 Replica Set(복제셋) 모드로 돌아가고 있어야 합니다. (MongoDB Atlas는 기본적으로 복제셋입니다.)
반응형
'Spring' 카테고리의 다른 글
| [Spring/JPA] N+1과 @OneToOne LEFT JOIN (0) | 2026.01.05 |
|---|---|
| [Spring/JPA] JPA에서 UNIQUE 제약조건 예외가 언제 발생하나? (0) | 2025.12.12 |
| [Spring/JPA] Spring Boot + JPA 페이징 (0) | 2025.12.11 |
| [Spring/JPA] Entity + Lombok Builder 사용 시 컬렉션 필드 초기화 주의점 (0) | 2025.11.26 |
| [Spring/MyBatis] No constructor found in ~ matching 오류 (0) | 2025.02.10 |