728x90

현재 작업중인 리소스 리팩토링 하는 과정에서 monggoDB 트랜잭션이 작동하지 않는다는 사실을 전달받았다.

이에 실제로 지원을 하지 않는 것인지 추가로 지원이 되는지 부터 확인했다.

아래는 참조 문서이다.

 

https://www.baeldung.com/spring-data-mongodb-transactions

 

문서를 보니 spring boot transaction 이 적용될려면 몇가지 조건이 필요하다.

 

  1. MongoDB 버전이 4.0 이상
  2. 레플리카 셋 적용

 

회사 몽고디비를 확인하니 4.0 버전이 설치가 되어 있지만 레플리카 셋이 적용 되지 않았다.

직접 작업에 참여한것도 아니고 이전에 일하는 사람이 하고 퇴사했다는 애기만 들었다.

회사에서는 AWS documentDB를 이용하기 떄문에 아마 비용문제로 하나만 했을거로 예상이 된다.

그래도 권장 사양이 있는데 좀 의아하긴하다.

 

일단 몽고디비의 레플리카 셋구조를 보면

 

 

첫번째는 하나의 primary DB에 2개의 복제본인 secondary DB 가 붙는 구조

 

 

 

두번 째는 하나의 secondary에 arbiter 가 붙는 구조

 

 

 

  1. primary - 단 하나만 존재 가능하며 실제 클라이언트와 정보를 주고 받음.
  2. secondary - 장애시 프라이머리로 전환이 가능하며 클라이언트 일기 작업 분담 가능 (slave db 처럼)
  3. arbiter - 레플리카셋을 3대 이상의 홀수로 구성할 수 없을시, 투표권만을 가지고 레플리카 셋을 모니터링 역할.

개념적으로 이해 했을때는 위와같이 복제 디비가 존재해야지만 트랜잭션 롤백이 가능한것 으로 보인다.

실제 설치형 DB 의 경우 추가 설정을 할게 추가로 존재하지만 AWS document DB 의 경우 추가로 생성만 해주면 된다.

아래는 실제 적용 코드이다.

 

 

@Configuration
@EnableTransactionManagement
@EnableMongoRepositories(basePackages = "kr.howser.partner.repository.mongo")
public class MongoConfig extends AbstractMongoClientConfiguration {

    @Value("${spring.data.mongodb.uri}")
    private String uri;

    @Value("${spring.data.mongodb.data-base}")
    private String dataBaseName;

    @Override
    @NonNull
    protected String getDatabaseName() {
        return this.dataBaseName;
    }

    @Override
    @NonNull
    public MongoClient mongoClient() {
        final ConnectionString connectionString = new ConnectionString(this.uri);
        final MongoClientSettings mongoClientSettings = MongoClientSettings.builder()
                .applyConnectionString(connectionString)
                .build();
        return MongoClients.create(mongoClientSettings);
    }

    @Primary
    @Bean(name = "mongoTransaction")
    public MongoTransactionManager transactionManager(MongoDatabaseFactory dbFactory) {
        return new MongoTransactionManager(dbFactory);
    }

    @Primary
    @Bean
    public MongoTemplate mongoTemplate() {
        MongoDatabaseFactory mongoDbFactory = new SimpleMongoClientDatabaseFactory(mongoClient(), this.dataBaseName);
        DbRefResolver dbRefResolver = new DefaultDbRefResolver(mongoDbFactory);
        MongoMappingContext mongoMappingContext = new MongoMappingContext();
        mongoMappingContext.setFieldNamingStrategy(new SnakeCaseFieldNamingStrategy());
        MappingMongoConverter converter = new MappingMongoConverter(dbRefResolver, mongoMappingContext);
        converter.setTypeMapper(new DefaultMongoTypeMapper(null));//_class delete
        return new MongoTemplate(mongoDbFactory, converter);
    }

}

 

 

위와같이 트랜잭션을 걸어주면 된다. 트랜잭션 빈 설정 오류시는 이름을 꼭 추가로 해주어야한다.

MongoDatabaseFactory mongoDbFactory = new SimpleMongoClientDatabaseFactory(mongoClient(), this.dataBaseName);
        DbRefResolver dbRefResolver = new DefaultDbRefResolver(mongoDbFactory);
        MongoMappingContext mongoMappingContext = new MongoMappingContext();
        mongoMappingContext.setFieldNamingStrategy(new SnakeCaseFieldNamingStrategy());
        MappingMongoConverter converter = new MappingMongoConverter(dbRefResolver, mongoMappingContext);
        converter.setTypeMapper(new DefaultMongoTypeMapper(null));//_class delete

 

 

 

이 부분의 경우 _class 를 지워줄때 사용한다. 필요한 부분이라 굳이 지워나 싶기는 하나 일단은 삭제 요청을 받아서 삭제가 되도록 ..

이번에 작업을 하면서 느끼지만 추가로 작업을 한다면 이론적인 부분 부터 꼭 하는 습관을 가지도록 더 정진해야겠다..

728x90

+ Recent posts