요구사항 1) 회원가입 시 User는 필수 약관 동의를 동의하지 않으면 가입할 수 없다. 2) 약관의 최초 생성 일자만 남기면 된다. (약관의 수정 일자는 저장하지 않아도 된다.) 3) 필수 약관 생성 또는 수정 시, 약관에 따라 User에게 동의를 구하지 않고 동의로 체크한다 . 4) 이 때, 공지사항은 약관 생성 또는 수정이 반영되기 이전에 관리자가 직접 게시한다.
1) 필수 약관 생성 Entity 생성
[module-common & module-admin] → TermsCondition
@Entity@NoArgsConstructor@Table(name = "terms_condition")publicclassTermsCondition{
@Id@Column(name = "terms_condition_id")@GeneratedValue(strategy = GenerationType.IDENTITY)private Long id;
private String title; // 약관 제목private String content; // 약관 내용private LocalDate createdAt; // 최초 생성 일자
}
→ 필수 약관 생성 시 무조건 필수 약관을 동의하는 MemberTermsAgreement 가 생성되어야 함
[module-admin] → TermsConditionServiceImpl
아래의 방식은 모든 Member에 대한 업데이트인데 하나씩 insert하는 방식은 성능상 좋지 않다
@Override@TransactionalpublicvoidcreateTermsCondition(CreateTermsConditionRequest request){
TermsCondition termsCondition = TermsCondition.builder()
.title(request.getTitle())
.content(request.getContent())
.createdAt(LocalDate.now())
.build();
termsConditionRepository.save(termsCondition);
// 필수 동의 체크를 위한 MemberTermsCondition -> 자동 생성/ User의 동의를 구하지 않음// 모든 멤버에 대해 동의 사항 생성
updateAllMembersToAgreeToTerms(termsCondition);
}
@TransactionalprivatevoidupdateAllMembersToAgreeToTerms(TermsCondition termsCondition){
List<Member> members = memberService.findAllMember();
for (Member member : members) {
memberTermsAgreementRepository.save(MemberTermsAgreement.builder()
.member(member)
.termsCondition(termsCondition)
.isAgreed(true)
.agreedAt(LocalDate.now())
.build()
);
};
}
성능 최적화 방법 가정: 3천명
1) Batch 처리
장점: JPA의 편리함을 유지하면서도 데이터를 일정 크기(batch size)로 나누어 처리할 수 있습니다. 메모리 사용량을 제한하고 성능을 최적화할 수 있습니다.
예시: 50개씩 처리하는 배치 처리 방식을 사용하면, 3천 명의 유저를 60개의 배치로 나누어 처리하게 됩니다. flush() 및 clear()를 통해 메모리 사용을 줄일 수 있습니다.
2) Native Query 사용
장점: SQL을 직접 사용하므로, 성능이 뛰어나고 데이터베이스에 대한 추가적인 부하가 적습니다. 특히, 대량의 데이터를 한 번에 처리할 수 있습니다.
예시: 모든 유저를 한 번의 쿼리로 업데이트하는 방식입니다. 이 방식은 간단하고, 3천 명의 유저를 한 번의 트랜잭션으로 처리할 수 있습니다.
원인: ON CONFLICT에 고유 제약 조건을 추가했지만 Entity를 생성할 때 고유 제약 조건으로 설정하지 않았기 때문
해결: MemberTermsAgreement 테이블에 고유 제약 조건 추가
"trace": "org.hibernate.exception.SQLGrammarException: JDBC exception executing SQL [INSERT INTO member_terms_agreement (member_id, terms_condition_id, is_agreed, agreed_at) SELECT m.member_id, ?, true, CURRENT_DATE FROM member m ON CONFLICT (member_id, terms_condition_id) DO UPDATE SET is_agreed = true, agreed_at = CURRENT_DATE] [ERROR: there is no unique or exclusion constraint matching the ON CONFLICT specification]