트랜잭션과 락(3) - 낙관적 락, 비관적 락

2024. 2. 15. 21:39spring/JPA

낙관적 락

JPA가 제공하는 낙관적 락은 버전(@Version)을 사용한다. 낙관적 락은 트랜잭션을 커밋하는 시점에 충돌을 알 수 있다는 특징이 있다.

 락 옵션 없이 @Version만 있어도 낙관적 락이 적용된다. 락 옵션을 사용하면 더 세밀하게 락을 제어할 수 있다.

 

옵션

1. NONE

락 옵션을 적용하지 않아도 엔티티에 @Version이 적용된 필드만 있으면 낙관적 락이 적용된다.

 

- 용도

조회한 엔티티를 수정할 때 다른 트랜잭션에 의해 변경되지 않아야 한다. 조회 시점부터 수정 시점까지를 보장한다.

 

- 동작

엔티티를 수정할 때 버전을 체크하면서 버전을 증가한다. 이때 데이터베이스의 버전 값이 현재 버전이 아니면 예외가 발생한다.

 

- 이점

두번의 갱신 분실 문제를 예방한다.

 

 

2. OPTIMISTIC

@Version만 적용했을 때는 엔티티를 수정해야 버전을 체크하지만 이 옵션을 추가하면 엔티티를 조회만 해도 버전을 체크한다.

 

- 용도

조회한 엔티티는 트랜잭션이 끝날 때까지 다른 트랜잭션에 의해 변경되지 않아야 한다. 조회 시점부터 트랜잭션이 끝날 때까지 조회한 엔티티가 변경되지 않음을 보장한다.

 

- 동작

트랜잭션을 커밋할 때 버전 정보를 조회해서 현재 엔티티의 버전과 같은지 검증한다.

 

- 이점

DIRTY READ와 NON-REPEATABLE READ를 방지한다.

 

 

3. OPTIMISTIC_FORCE_INCREMENT

낙관적 락을 사용하면서 강제로 버전을 증가시킨다.

 

- 용도

논리적인 단위의 엔티티 묶음을 관리할 수 있다. 예를 들어 게시물과 첨부파일이 일대다, 다대일의 양방향 연관관계이고 첨부파일이 연관관계의 주인이다. 게시물을 수정하는데 첨부파일만 추가한다면 게시물의 버전은 증가하지 않는다.

 => (게시물 테이블은 변경되지 않았음)

해당 게시물은 물리적으로 변경되지 않았지만 논리적으로 변경되었다. 이때 게시물의 버전도 강제로 증가시킬 때 사용된다.

 

 - 동작

엔티티를 수정하지 않아도 트랜잭션을 커밋할 때 UPDATE 쿼리를 사용해서 버전 정보를 강제로 증가시킨다.

 

- 이점

강제로 버전을 증가해서 논리적인 단위의 엔티티 묶음을 버전 관리할 수 있다.

 

 

비관적 락

JPA가 제공하는 비관적 락은 데이터베이스 트랜잭션 락 메커니즘에 의존하는 방법이다. 주로 SQL 쿼리에 SELECT FOR UPDATE 구문을 사용하면서 시작하고 버전 정보는 사용하지 않는다. 비관적 락은 주로 PESSIMISTIC_WRITE 모드를 사용한다.

 

비관적 락은 다음과 같은 특징이 있다.

- 엔티티가 아닌 스칼라 타입을 조회할 때도 사용할 수 있다.

- 데이터를 수정하는 즉시 트랜잭션 충돌을 감지할 수 있다.

 

옵션

1. PESSIMISTIC_WRITE

데이터베이스에 쓰기 락을 걸 때 사용한다.

 

- 용도

데이터베이스에 쓰기 락을 건다.

 

- 동작

데이터베이스 SELECT FOR UPDATE를 사용해서 락을 건다.

 

 

2. PESSIMISTIC_READ

데이터를 반복 읽기만 하고 수정하지 않는 용도로 락을 걸 때 사용한다. 일반적으로 잘 사용하지 않는다.

 

3. PESSIMISTIC_FORCE_INCREMENT

비관적 락중 유일하게 버전 정보를 사용한다. 비관적 락이지만 버전 정보를 강제로 증가시킨다.