실전프로젝트 6일차. 오늘은 redis를 하루종일 적용해보느라 고생했다. 이 내용은 내일 올리도록 하고 오늘은 어제 정리못한 jmeter 테스트 당시 발생했던 LockAcquisition Exception 처리를 올리도록 하겠다.
@Transactional
public Long makeReservations(ReservationRequestDto dto, User user, Long ticketInfoId) {
TicketInfo ticketInfo = ticketInfoRepository.findById(ticketInfoId).orElseThrow(
() -> new IllegalArgumentException("공연회차 정보가 없습니다.")
);
if (!ticketInfo.isAvailable()) {
throw new IllegalArgumentException("현재 예매가 불가능한 공연입니다.");
}
if (ticketInfo.getTotalSeats() >= ticketInfo.getReservedSeats() + dto.getCount()) {
ticketInfo.reserveSeats(dto.getCount());
// 만약 ReservedSeats와 TotalSeats가 같아지면 isAvailable을 false로 변경
if (ticketInfo.getTotalSeats() == ticketInfo.getReservedSeats()) {
ticketInfo.setAvailable(false);
}
ticketInfoRepository.save(ticketInfo);
Reservation reservation = new Reservation(dto, user, ticketInfo);
reservationRepository.saveAndFlush(reservation);
return reservation.getId();
}
throw new IllegalArgumentException("남은 자리가 없습니다");
}
Isolation Level을 Read Uncommitted, Read Committed, Repeatable Read로 조정해봤으나 큰 차이 x
.saveAndFlush를 .save로 바꿔봤으나 실패
RDS 스펙 업그레이드
db.t2.micro 프리티어 가장 기본에서 db.t4g.micro로 업그레이드 해봤으나 차이 x.
Post말고 Get으로 단순 db조회로 요청을 바꾸니 10000명까지 문제가 없어 RDS 문제는 아니었다.
TicketInfo에서 다른 트랜잭션끼리 동일한 자원을 수정하는 과정에서 발생한 문제라고 생각해서 로직 삭제 후 테스트 해보니 10000명까지 문제가 안나서 이걸 문제의 원인으로 잡았다.
그래서 일단 Optimistic Lock으로 TicketInfo에
@Version
private Long version;
을 만들어 시도해봤으나 실패. 여기서 Optimistic Lock이 잘 적용되었는지는 모르겠다.
추후 한번 더 시도해볼 예정.
public interface TicketInfoRepository extends JpaRepository<TicketInfo, Long> {
@Lock(LockModeType.PESSIMISTIC_WRITE)
@Query("SELECT t FROM TicketInfo t WHERE t.id = :id")
Optional<TicketInfo> findByIdWithLock(@Param("id") Long id);
}
이렇게 하니 LockAcquisition Exception이 발생하지 않고 아래와 같은 결과를 얻었다.