📗

Pessimistic Lock vs. Optimistic Lock

Pessimistic Lock(비관적 락) vs. Optimistic Lock(낙관적 락)

두 번의 갱신 분실 문제(Second lost updates problem)

두 트랜잭션에서 데이터 변경 → 최종적으로 한 트랜잭션의 결과만 남는 것
⇒ 해결: 마지막 커밋만 인정 / 최초의 커밋만 인정 / 충돌하는 갱신 내용 병합
⇒ JPA에서는 비관적 락/낙관적 락 매커니즘 제공

Pessimistic

트랜잭션의 충돌이 발생한다고 가정
트랜잭션이 시작될 때 데이터베이스에 락 → 다른 트랜잭션 접근 X
Shared Lock(공유 락, S Lock)
특정 Row 읽을(Read) 때 사용
여러 트랜잭션이 동시에 한 Row에 S Lock 걸 수 있음
하나의 Row를 여러 트랜잭션이 동시에 읽을 수 있음
S Lock이 설정된 Row에는 X Lock 사용 X
InnoDB에서 일반적인 SELECT 쿼리는 Lock 사용 X
But, SELECT … FOR SHARE 등의 일부 쿼리는 각 Row에 Shared Lock 검
Exclusive Lock(배타 락, X Lock)
특정 Row를 변경(Write)할 때 사용
X Lock이 설정된 Row에는 다른 트랜잭션을 읽기 위해 S Lock 걸거나, 쓰기 위해 X Lock 걸 수 X
쓰기 작업을 하고 있는 Row에는 모든 접근 불가
SELECT … FOR UPDATE, UPDATE, DELETE 등의 수정 쿼리들이 실행될 때 Row에 걸림
커스텀 메서드에 @Lock 어노테이션 붙이고 Lock 어노테이션의 설정 값인 value에 설정하고자 하는 LockModeType을 지정해주면 됨
PESSIMISTIC_READ, PESSIMISTIC_WRITE, PESSIMISTIC_FORCE_INCREMENT
public interface TransactionRepository extends JpaRepository<Transaction, Long> { @Lock(value - }
Java
복사

Optimistic

대부분의 트랜잭션은 충돌이 발생하지 않는다고 낙관적으로 가정
데이터베이스가 제공하는 락 X 애플리케이션 레벨에서 락 구현( 비관적 락)
⇒ 트랜잭션 커밋 전까지 충돌 알 수 없음
@Version → 해당 엔티티 테이블 읽는 각 트랜잭션은 업데이트 수행하기 전 버전의 속성 확인
IF. 업데이트 하기 이전에 버전 값 변경 → OptimisticLockException 발생
각 엔티티 클래스에는 한 개의 버전 필드만 있어야 함
여러 테이블에 매핑된 엔티티의 기본 테이블에 배치해야 함
버전 유형: int, Integer, long, Long, short, Short, java.sql.Timestamp
엔티티 ~> 버전이 어떠한지 필드 탐색 O 직접 수정 X
벌크 연산시 JPA가 관리 X → 직접 +1
@Entity @NoArgsConstructor @AllArgsConstructor public class Account { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @Version private int version; ... }
Java
복사
비관적 락
데이터베이스 레벨의 락 → 데이터의 무결성 But, 성능상 손해
충돌 ↑ → 잦은 롤백으로 인한 효율성 문제 발생하는 것이 예상되는 시나리오에 사용
낙관적 락
실제로 데이터 충돌 자주 일어나지 않을 것이라고 예상되는 시나리오에 사용
But, 추가적인 오류 처리 + 동시 접근 ↑ → 오류 처리를 위해 더 많은 리소스 소모

그래서 우리 프로젝트는?

특징
분산 락
비관적 락
적용 범위
분산 환경에서 여러 노드에 걸쳐 동작
단일 데이터베이스 내에서만 동작
성능
네트워크 호출 비용
DB 트랜잭션 처리 속도에 의존
확장성
분산 환경에서도 적합
확장성 제한(단일 DB 노드 중심)
일관성 보장
네트워크 상태 → 정합성 위험
강력한 일관성
데드락 가능성
낮음(TTL 설정으로 방지 가능)
높음(교착 상태 발생 가능)
데이터베이스 분산 → 분산 락