JPA의 동시성 제어: 낙관적 락 vs 비관적 락

데이터베이스를 다룰 때 동시성 제어는 매우 중요한 이슈입니다. JPA에서는 이를 위해 두 가지 주요 전략인 낙관적 락(Optimistic Lock)과 비관적 락(Pessimistic Lock)을 제공합니다. 이 두 전략의 특징과 사용법, 그리고 언제 어떤 전략을 선택해야 할지 알아보겠습니다.

1. 낙관적 락 (Optimistic Lock)

특징

  • 데이터 충돌이 드물게 발생한다고 가정합니다.
  • 실제로 데이터를 수정할 때 충돌을 감지합니다.
  • 주로 버전(version) 컬럼을 사용하여 구현합니다.

작동 방식

  1. 엔티티를 읽을 때 버전 정보도 함께 읽습니다.
  2. 데이터 수정 시 버전 정보를 확인합니다.
  3. 버전이 일치하면 수정을 진행하고 버전을 증가시킵니다.
  4. 버전이 불일치하면 예외를 발생시킵니다.

구현 예시

@Entity
public class User {
    @Id
    private Long id;
    
    private String name;
    
    @Version
    private Long version;
}

장점

  • 데이터베이스 락을 사용하지 않아 성능상 이점이 있습니다.
  • 애플리케이션 레벨에서 충돌을 처리할 수 있습니다.

단점

  • 충돌 발생 시 재시도 로직을 직접 구현해야 합니다.

2. 비관적 락 (Pessimistic Lock)

특징

  • 데이터 충돌이 자주 발생한다고 가정합니다.
  • 데이터를 읽는 시점에 락을 겁니다.
  • 데이터베이스의 락 기능을 사용합니다.

작동 방식

  1. 데이터를 읽을 때 락을 획득합니다.
  2. 트랜잭션이 완료될 때까지 다른 트랜잭션의 접근을 막습니다.
  3. 트랜잭션 완료 후 락을 해제합니다.

구현 예시

@Lock(LockModeType.PESSIMISTIC_WRITE)
@Query("SELECT u FROM User u WHERE u.id = :id")
User findByIdWithPessimisticLock(@Param("id") Long id);

장점

  • 데이터 일관성을 강하게 보장합니다.
  • 충돌 처리 로직이 단순합니다.

단점

  • 동시성이 떨어져 성능 저하가 발생할 수 있습니다.
  • 데드락 발생 가능성이 있습니다.

어떤 락을 선택해야 할까?

낙관적 락 선택 기준

  • 충돌이 적게 발생하는 경우
  • 높은 동시성이 필요한 경우
  • 짧은 트랜잭션 시간

비관적 락 선택 기준

  • 데이터 정합성이 매우 중요한 경우
  • 충돌이 자주 발생하는 경우
  • 긴 트랜잭션 시간

결론

JPA의 낙관적 락과 비관적 락은 각각 장단점이 있습니다. 낙관적 락은 성능과 동시성에 이점이 있지만, 충돌 처리를 위한 추가 로직이 필요합니다. 비관적 락은 데이터 일관성을 강하게 보장하지만, 성능 저하의 가능성이 있습니다.

따라서 실제 사용 시에는 비즈니스 요구사항, 성능, 데이터 일관성 등을 종합적으로 고려하여 적절한 락 전략을 선택해야 합니다. 때로는 두 전략을 혼합하여 사용하는 것도 좋은 방법이 될 수 있습니다.