mongoDB는 id를 String 형태의 문자열로 구성하고 있고, 이를 강제로 Long으로 바꾸어 사용할 수 있지만, 그럴 경우 MongoRepository의 findBy 관련 함수들을 많이 튜닝해줘야 하는 단점이 보였기에 별도로 Long 형태의 idx를 collection에 추가하여 사용하려 합니다. RDS에서 제공하는 auto increment기능이 noSQL에는 없기 때문에, 각 collection의 idx 마지막 값을 저장하는 별도의 collection을 구성하여 auto increment 기능을 구현하였습니다.
1. collection들의 마지막 idx를 가지고 있는 DatabaseSequence Class 생성하기
- members collection의 Long idx의 마지막 값을 가지는 database_sequences라는 명칭의 새로운 collection을 만들어서 사용해야 하므로 모델 개념의 클래스를 생성합니다.
ackage com.kimmingyu.aws.model;
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;
@Document(collection = "database_sequences")
public class DatabaseSequence {
@Id
private String id;
private long seq;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public long getSeq() {
return seq;
}
public void setSeq(long seq) {
this.seq = seq;
}
}
2. members Model에 SEQENCE_NAME 선언 및 Long idx 추가
- members 모델 안에 @Transient 어노테이션을 사용하여 SEQUENCE_NAME을 지정합니다.
- Long 형태의 idx도 추가합니다.
- users에서 사용할 거면 users_sequence, boards에서 사용할 거면 boards_sequence 등 일관성 있게 명명
ackage com.kimmingyu.aws.model;
import org.springframework.data.annotation.Id;
import org.springframework.data.annotation.Transient;
import org.springframework.data.mongodb.core.index.Indexed;
import org.springframework.data.mongodb.core.mapping.Document;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Size;
@Document(collection = "members")
public class Member {
@Transient
public static final String SEQUENCE_NAME = "members_sequence";
@Id
private String id;
private Long idx;
@NotBlank
@Size(max = 10)
private String name;
@NotBlank
@Size(max = 100)
@Indexed(unique = true)
private String email;
@NotBlank
@Size(min = 10)
private String password;
private String phone;
private String regDate;
// getter & setter ...
}
3. Auto Increment 기능을 담당하는 SequenceGeneratorService 클래스 생성하기
- 해당 collection에 대한 idx값이 없으면 1부터 idx를 시작하고
- 해당 collection에 대한 idx값이 있으면 다음 숫자로 업데이트하여 자동 증가 기능을 담당해주는 서비스 클래스 생성합니다.
package com.kimmingyu.aws.service.classes;
import com.kimmingyu.aws.model.DatabaseSequence;
import static org.springframework.data.mongodb.core.FindAndModifyOptions.options;
import static org.springframework.data.mongodb.core.query.Criteria.where;
import static org.springframework.data.mongodb.core.query.Query.query;
import java.util.Objects;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.MongoOperations;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.stereotype.Service;
@Service
public class SequenceGeneratorService {
private MongoOperations mongoOperations;
@Autowired
public SequenceGeneratorService(MongoOperations mongoOperations) {
this.mongoOperations = mongoOperations;
}
public long generateSequence(String seqName) {
DatabaseSequence counter = mongoOperations.findAndModify(query(where("_id").is(seqName)),
new Update().inc("seq",1), options().returnNew(true).upsert(true),
DatabaseSequence.class);
return !Objects.isNull(counter) ? counter.getSeq() : 1;
}
}
4. Member 관련 Controller에서 위의 구현체들을 사용하여 저장하기
// Member Class
@PostMapping(value = "/save", produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<?> saveOrUpdateMember(@RequestBody MemberDTO memberDTO) {
// sequenceGeneratorService를 사용하여 setIdx 해주기
memberDTO.setIdx(sequenceGeneratorService.generateSequence(Member.SEQUENCE_NAME));
// Update
memberService.saveOrUpdateMember(ObjectMapperUtils.map(memberDTO, Member.class));
}
5. 확인하기
'Spring Boot' 카테고리의 다른 글
RabbitMQ 활용하기 (8) | 2024.09.30 |
---|---|
스프링에서 TransactionManager에 대한 상세한 이해하기 (2) | 2024.09.24 |
Spring Boot에서 @Transactional 어노테이션이 작동하지 않을 때 해결 방법 (0) | 2024.09.24 |
Spring Boot 및 MongoDB를 사용하여 REST API 구축하기 - 회원 가입,탈퇴,조회 (3) | 2022.07.19 |
IntelliJ에서 Spring Boot 프로젝트 생성 및 실행하기 (1) | 2022.06.16 |