@Transactional
suspend fun save(requestDto: SignUpRequestDto): UserResponseDto {
val user = User(
email = requestDto.email,
name = requestDto.name,
password = passwordEncoder.encode(requestDto.password),
nickname = requestDto.nickname,
)
val save = userService.save(user)
throw IllegalArgumentException("Test Ex")
return UserResponseDto.from(save)
}
위의 코드 처럼 예외 발생시 트랜잭션 롤백 테스트를 해보았는데, 데이터가 롤백이 되지 않는 것을 확인할 수 있었다.
그러면 어떻게 해야할까??
먼저, TransactionManager와 TransactionOperator를 빈으로 등록하자.
@Configuration
@EnableReactiveMongoRepositories(basePackages = ["xxx.xxxx"])
class MongoConfig {
@Bean
fun transactionManager(reactiveMongoDatabaseFactory: ReactiveMongoDatabaseFactory): ReactiveMongoTransactionManager {
return ReactiveMongoTransactionManager(reactiveMongoDatabaseFactory)
}
@Bean
fun transactionalOperator(reactiveTransactionManager: ReactiveMongoTransactionManager): TransactionalOperator {
return TransactionalOperator.create(reactiveTransactionManager)
}
}
그러면 제대로 되는가?? 아니다. 어플리케이션을 실행하면 예외가 발생한다.
MongoDB 트랜잭션 관리를 하기위해서는 Stand-alone이 아닌 Replica Set을 구성해야 한다.
openssl rand -base64 756 > mongodb.key
chmod 400 mongodb.key
sudo chown 999:999 mongodb.key // ec2 환경에서 안할 경우 문제가 생길 수 있음
version: "3.8"
services:
mongo1:
image: mongo
hostname: mongo1
container_name: mongo1
ports:
- "27017:27017"
volumes:
- data-mongo1:/data/db
- ./mongodb.key:/etc/mongodb.key
environment:
- MONGO_INITDB_ROOT_USERNAME=pmeet_user
- MONGO_INITDB_ROOT_PASSWORD=pmeet_pwd
- MONGO_INITDB_DATABASE=pmeet
command: 'mongod --replSet myReplicaSet --keyFile /etc/mongodb.key --bind_ip_all'
mongo2:
image: mongo
hostname: mongo2
container_name: mongo2
depends_on:
- mongo1
ports:
- "27018:27017"
volumes:
- data-mongo2:/data/db
- ./mongodb.key:/etc/mongodb.key
environment:
- MONGO_INITDB_ROOT_USERNAME=pmeet_user
- MONGO_INITDB_ROOT_PASSWORD=pmeet_pwd
- MONGO_INITDB_DATABASE=pmeet
command: 'mongod --replSet myReplicaSet --keyFile /etc/mongodb.key --bind_ip_all'
mongo3:
image: mongo
hostname: mongo
container_name: mongo3
depends_on:
- mongo2
ports:
- "27019:27017"
volumes:
- data-mongo3:/data/db
- ./mongodb.key:/etc/mongodb.key
environment:
- MONGO_INITDB_ROOT_USERNAME=pmeet_user
- MONGO_INITDB_ROOT_PASSWORD=pmeet_pwd
- MONGO_INITDB_DATABASE=pmeet
command: 'mongod --replSet myReplicaSet --keyFile /etc/mongodb.key --bind_ip_all'
volumes:
data: { }
data-mongo1: { }
data-mongo2: { }
data-mongo3: { }
networks:
default:
name: mongodb_network
docker exec -it mongo1 mongosh -u pmeet_user -p pmeet_pwd --authenticationDatabase admin
위 명령어로 컨테이너에 진입하여 아래의 명령어를 입력하면 된다.
rs.initiate({
_id: "myReplicaSet",
members: [
{ _id: 0, host: "mongo1" },
{ _id: 1, host: "mongo2" },
{ _id: 2, host: "mongo3" }
]
});
위와 같이 ok: 1 이 나오면 성공이다!
이제 롤백 테스트를 해보면 성공적으로 되는 것을 확인 할 수 있다.