트랜잭션 락
1. 비관적 락 (Pessimistic Lock)
설명
데이터 충돌 가능성이 높다고 가정하고 트랜잭션이 데이터에 접근할 때마다 락을 걸어 다른 트랜잭션의 접근을 제한하는 방식으로, 즉 비관적인 관점에서 데이터 충돌을 사전에 방지하는 방식이다.
DB 락의 공유락, 베타락 기법을 사용하는 방식이다. (각 DB 락의 세부적인 설명은 다음 데이터베이스 락 게시글에서 확인할 수 있다.)
특징
- 강제 잠금: 데이터 (레코드) 읽기 또는 수정 시 다른 트랜잭션이 해당 데이터를 사용할 수 없도록 락을 걸어 데이터 충돌 완전히 방지
- 실시간 대기: 락이 해제될 까지는 다른 트랜잭션은 대기
- 트랜잭션의 지연 증가 가능성: 대기 시간이 길어질 경우 성능 저하가 일어날 수 있음
사용 예시
Spring JPA에서 @Lock
어노테이션과 LockModeType.PESSIMISTIC_WRITE
또는 PESSIMISTIC_READ
를 활용하여 사용한다.
읽기 전용 잠금 (PESSIMISTIC_READ
)
데이터 읽기만 허용하고 수정은 제한한다.
@Lock(LockModeType.PESSIMISTIC_READ)
@Query("SELECT l FROM Lecture l WHERE l.id = :id")
fun findByIdWithReadLock(@Param("id") id: Long): Lecture
쓰기 전용 잠금 (PESSIMISTIC_WRITE
)
데이터 읽기/수정 시 다른 트랜잭션이 접근하지 못하도록 잠금
@Lock(LockModeType.PESSIMISTIC_WRITE)
@Query("SELECT l FROM Lecture l WHERE l.id = :id")
fun findByIdWithWriteLock(@Param("id") id: Long): Lecture
2. 낙관적 락 (Optimistic Lock)
설명
데이터 충돌 가능성이 낮다고 가정하고 충돌이 발생하면 트랜잭션을 롤백하거나 재시도하는 방식으로, DB Lock을 사용하는 방식이 아닌 데이터를 수정할 때 데이터의 버전 정보를 활용하는 방식이다.
특징
- 버전 기반 제어: 데이터 변경 시 현재 버전 정보를 확인하여 충돌 여부 검증
- 낮은 대기 시간: 락이 없어도 작업을 진행할 수 있어 성능 저하가 적다.
- 재시도 필요: 만약 낙관적 락 충돌 발생 시
OptimisticLockException
예외가 발생하여 재시도 처리가 필요
사용 예시
Spring JPA에서 @Version
어노테이션을 사용해 구현한다.
엔티티에 @Version
추가
@Entity
class Lecture(
val title: String,
@Version
var version: Int? = null
) {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
var id: Long = 0
}
데이터 변경 시 JPA가 자동으로 버전 정보를 검증하는 방식이다.
정리
항목 | 비관적 락 (Pessimistic Lock) | 낙관적 락 (Optimistic Lock) |
---|---|---|
충돌 발생 가능성 | ⏫높음 (충돌 방지) | ⏬낮음 (충돌 허용) |
동작 방식 | 데이터 (레코드)에 잠금 설정 | 버전 정보를 이용해 충돌 검증 |
성능 | ⏬잠금과 대기로 인해 성능 저하 가능 | ⏫DB 락을 사용하지 않으므로 높은 성능 |
적합한 상황 | ⏫데이터 수정 충돌이 빈번한 경우 | ⏬데이터 수정 충돌이 드문 경우 |
데드락 | ❌발생 가능 (충돌 시 대기하기 때문) | ✅발생하지 않음 (충돌 시 예외 발생) |
재시도 필요 | ❌없음 | ✅충돌 발생 시 재시도 처리 필요 |