Conversation
| if (bookItemRepository.findByManagementNumber(managementNumber) != null) { | ||
| return BookItemError.DUPLICATE_MANAGEMENT_NUMBER.err() | ||
| } | ||
|
|
||
| val bookItem = bookItemRepository.save(BookItem(bookId = bookId, managementNumber = managementNumber)) |
There was a problem hiding this comment.
[MEDIUM] managementNumber 유일성 검사가 check-then-act라 동시 요청 시 중복 등록 가능
Problem: findByManagementNumber 조회 후 save를 호출하는 비원자적(check-then-act) 패턴이라, 동시에 같은 관리번호로 등록 요청이 들어오면 두 요청 모두 중복 검사를 통과한 뒤 각각 저장되어 "전체 고유해야 한다"는 요구사항이 깨질 수 있습니다.
Evidence: BookItem.managementNumber(BookItem.kt)는 @Column(nullable = false)만 있고 unique = true나 DB 유니크 인덱스가 없습니다. 이 저장소는 동일한 패턴(isbn 중복 체크)을 이미 겪었고, mysql/index.sql에 ux_books_active_isbn 유니크 인덱스를 추가해 CreateBookService/UpdateBookService의 동일한 레이스 컨디션을 막은 전례가 있습니다. book_items.management_number에는 그에 대응하는 인덱스가 없습니다.
Fix direction: mysql/index.sql에 book_items.management_number용 유니크 인덱스를 추가하고, CreateBookItemService에서 저장 시 발생하는 유니크 제약 위반 예외를 잡아 DUPLICATE_MANAGEMENT_NUMBER로 변환하세요.
There was a problem hiding this comment.
수정 완료
book_items.management_number 유니크 인덱스를 추가
DUPLICATE_MANAGEMENT_NUMBER 예외 처리는 진행하지 않고 기존 isbn 케이스(CreateBookService/UpdateBookService)에서 DataIntegrityViolationException을 전역으로 잡아 공통 DATA_CONFLICT(409)로 응답하고 있어서 해당 방식으로 처리
연관 이슈
작업 사항
feat(#10): 소장본 등록 API 추가(주제)-(번호)형식 검증, 전체 고유 여부 검사feat(#10): 소장본 상태 변경 API 추가LOST또는DISPOSED로만 변경 가능하도록 검증테스트
주의 사항 및 참고사항