@Bean public MongoClient mongoClient() { Stringconnection="mongodb://" + username + ":" + password + "@" + host + ":27017/" + databaseName + "?replicaSet=rs0"; return MongoClients.create(newConnectionString(connection)); // MongoDB 연결 URI }
/** * Replica Set 에서 동작할 MongoTransactionManager Bean 생성 */ @Bean public MongoTransactionManager transactionManager(MongoDatabaseFactory dbFactory) { returnnewMongoTransactionManager(dbFactory); }
/** * class 필드 제거를 위해 AbstractMongoClientConfiguration 오버라이딩 * AbstractMongoClientConfiguration 에서 아래 Bean 등록해줌 * - MongoClient * - MongoTemplate */ @Override public MappingMongoConverter mappingMongoConverter(MongoDatabaseFactory databaseFactory, MongoCustomConversions customConversions, MongoMappingContext mappingContext) { DbRefResolverdbRefResolver=newDefaultDbRefResolver(databaseFactory); MappingMongoConverterconverter=newMappingMongoConverter(dbRefResolver, mappingContext); converter.setCustomConversions(customConversions); converter.setCodecRegistryProvider(databaseFactory); // _class 필드 제거 converter.setTypeMapper(newDefaultMongoTypeMapper(null)); return converter; }
Spring Data Mongo 에는 org.mongodb:mongodb-driver-core 라이브러리도 포함되어 있어 MongoTemplate 사용또한 가능하다.
다음과 같은 상황에선 MongoTemplate 을 사용하느게 효과적이다.
동적쿼리
집계쿼리(Aggregation)
배치쿼리
upsert
1 2 3 4 5 6 7 8 9 10 11 12 13
privatefinal MongoTemplate mongoTemplate;
/** * username과 email을 동적으로 조건에 따라 조회 */ public UserDocument getUserByParam(String username, String email) { Queryquery=newQuery().addCriteria(Criteria.where("username").is(username)); // 동적 조건 추가 if (email != null) { query.addCriteria(Criteria.where("email").is(email)); } return mongoTemplate.findOne(query, UserDocument.class); }
save, insert
1 2 3 4 5 6 7 8 9
// 새 문서 삽입 db.collection.insert({ name: "홍길동", age: 30 }); db.collection.save({ name: "이순신", age: 40 });
// id 지정해서 insert, id 가 이미 존재한다면 예외발생 db.collection.insert({ _id: ObjectId("1234"), name: "홍길동", age: 30 });
// id 지정해서 save, id 가 없다면 추가, 있다면 업데이트함. db.collection.save({ _id: ObjectId("1234"), name: "이순신", age: 41 });
동작에는 큰 차이가 없지만 명시적으로 save, insert 를 구분해서 사용하는것을 권장한다.
Spring Data Mongo 에서 다중삽입의 경우 saveAll 함수는 반복문이고 insert(list) 는 일괄처리임으로 성능상에도 차이가 있다.
트랜잭션
MongoDB 트랜잭션은 Oplog 를 지원하는 Cluster 환경(Replica Set, Sharded Cluster) 환경에서만 동작한다. Spring Data Mongo 에선 org.springframework.transaction.annotation.Transactional 어노테이션을 지원하여 쉽게 트랜잭션 구현이 가능하다.
1 2 3 4 5 6 7 8 9 10 11 12
@Transactional public UserDocument createUser(CreateUserRequestDto requestDto) { UserDocumentuser= userRepository.save(newUserDocument(requestDto.getUsername(), requestDto.getEmail())); // if (true) throw new IllegalArgumentException(""); // 트랜잭션 확인용 UserDetailDocumentuserDetail= userDetailRepository.save(newUserDetailDocument( user.getId(), requestDto.getAge(), requestDto.getGender(), requestDto.getNickname(), requestDto.getDesc())); return user; }
주석을 해제하고 고의로 예외를 발생시키면 UserDocuemnt 저장요청도 롤백된다.
세밀하게 트랜잭션 구간을 나누고 싶다면 아래 직접 트랜잭션 구간을 설정할 수 있다.
transactionTemplate(주로사용)
mongoTemplate.withSession(session)
MongoOperations
TransactionTemplate 을 사용하려면 Bean 으로 등록해야한다.
1 2 3 4
@Bean public TransactionTemplate transactionTemplate(MongoTransactionManager transactionManager) { returnnewTransactionTemplate(transactionManager); }