inblog logo
|
LifeLog, DevLog
    JPA

    JPA LOCK

    낙관적 락, 비관적 락
    KYJTHEYJ's avatar
    KYJTHEYJ
    Feb 10, 2026
    JPA LOCK
    Contents
    LOCK낙관적 락 (Optimistic Lock)비관적 락 (Pessimistic Lock)PESSIMISTIC_READ, 공유 락PESSIMISTIC_WRITE, 배타 락

    LOCK

    다량의 접근이 예상되는 서비스의 경우엔
    데이터 관리에 있어 동시에 접근하는 경우를 고려해야 한다

    데이터의 일관성이 깨지거나 (중복 발행 등), 한정된 데이터지만
    초과될 수 있기 때문이다

    DB Lock 과 똑같은 개념이지만 적용법이 JPA다 보니 소개하게 되었다

    낙관적 락 (Optimistic Lock)

    데이터 변경시의 충돌을 감지하는 하여 충돌이 발생하면 그 때마다 재시도 하는 방식

    @Version 어노테이션을 통해 버전 번호를 붙여 충돌 여부를 판단

    실패 해도 되는 비즈니스 로직에 사용

    실질적으로 DB 락을 걸지 않아 성능이 보장되나 충돌이 잦을 경우엔 오히려 성능이 하락 (계속되는 재시도)

    @Entity                                                                       
      @Table(name = "order_sequence") 
      public class OrderSequence {                                          
          @Id                                                                
          private LocalDate seqDate;                                         
          private Integer currentSeq;    
                                             
          @Version  // 낙관적 락                                           
          private Long version;        
                                               
          public void incrementSeq() {                                        
              this.currentSeq++;                                             
          }                                                                   
      } 
    

    재시도 코드가 반드시 포함되어야함

     @Service
     @RequiredArgsConstructor
     public class OrderService {
         private final OrderSequenceRepository sequenceRepository;
    
         @Transactional
         public String generateOrderNo() {
             int retryCount = 0;
             int maxRetries = 3;
    
             while (retryCount < maxRetries) {
                 try {
                     LocalDate today = LocalDate.now();
    
                     OrderSequence sequence = sequenceRepository
                         .findById(today)
                         .orElse(new OrderSequence(today, 0));
    
                     sequence.incrementSeq();
                     sequenceRepository.save(sequence); // 여기서 버전 체크                                                                                                                                                                                                                                                             
    
                     return String.format("ORDER-%s-%04d",
                         today.format(DateTimeFormatter.ofPattern("yyyyMMdd")),
                         sequence.getCurrentSeq()
                     );
    
                 } catch (OptimisticLockException e) {
    		             // 재시도 코드
                     retryCount++;
                     if (retryCount >= maxRetries) {
                         throw new ServiceErrorException("주문번호 생성 실패");
                     }
                     // 잠시 대기 후 재시도                                                                                                                                                                                                                                                                                              
                     Thread.sleep(50);
                 }
             }
    
             throw new ServiceErrorException("주문번호 생성 실패");
         }
     }                                           
    

    비관적 락 (Pessimistic Lock)

    데이터의 충돌이 날 것이라고 가정하고 데이터를 락 후에 해제하며 순차 처리 하는 방식

    실패하면 안되는 비즈니스 로직에 사용

    락을 걸고 있어 성능이 느릴 수 있음

    PESSIMISTIC_READ, 공유 락

    다른 쓰레드가 읽기만 가능, 쓰기는 불가

    PESSIMISTIC_WRITE, 배타 락

    다른 쓰레드가 읽거나 쓰는 것 자체가 불가능

    한 쓰레드가 완전히 독점하는 방식

      @Repository                                                                 
      public interface OrderSequenceRepository extends JpaRepository<OrderSequence, LocalDate> {
    	  @Lock(LockModeType.PESSIMISTIC_WRITE)  // 비관적 락                                                 
        @Query("SELECT s FROM OrderSequence s WHERE s.seqDate = :date")
        Optional<OrderSequence> findBySeqDateWithLock(@Param("date") LocalDate date);
      }  
    
    Share article
    Contents
    LOCK낙관적 락 (Optimistic Lock)비관적 락 (Pessimistic Lock)PESSIMISTIC_READ, 공유 락PESSIMISTIC_WRITE, 배타 락

    LifeLog, DevLog - https://github.com/KYJTHEYJ

    RSS·Powered by Inblog