이름 그대로 비관적 락은 자원 경쟁을 비관적으로, 낙관적 락은 낙관적으로 본다.
비관적 락은 Repeatable Read 또는 Serializable 정도의 격리성 수준을 제공한다.
트랜잭션이 시작될 때 Shared Lock 또는 Exclusive Lock을 걸고 시작한다.
공유락 (Shared Lock)
: Read Lock이라고도 불리는 공유락은 트랜잭션이 읽기를 할 때 사용하는 락이며, 데이터를 읽기만하기 때문에 같은 공유락끼리는 동시에 접근이 가능하지만, write 작업은 막는다.
배타락 (Exclusive Lock)
: Write Lock이라고도 불리며, 데이터를 변경할 때 사용하는 락이다. 트랜잭션이 완료될 때까지 유지되며, 배타락이 끝나기 전까지 read/write를 모두 막는다.
자원에 락을 걸지 않고, 동시성 문제가 발생하면 그때 처리 한다.
낙관적 락은 수정할 때 수정했다고 명시하여 다른 트랜잭션이 동일한 조건으로 값을 수정할 수 없게 하는 것이다.
낙관적 락은 version과 같은 별도의 컬럼을 추가하여 충돌 발생을 막는다.
일반적으로 version(hashcode/timestamp를 사용할 수도 있다)
의 상태를 보고 충돌을 확인한다.
충돌이 발생했을때, DB가 아닌 애플리케이션 단에서 처리 한다.
낙관적 락은 UPDATE에 실패해도 자동으로 예외를 던지지 않고, 단순히 0개의 row를 업데이트 한다. 따라서 이때 여러 작업이 묶인 트랜잭션 요청이 실패할 경우, 개발자가 직접 롤백 처리
를 해줘야 한다.
@Version
을 통해 낙관적 락을 사용할 수 있으며, 낙관적 락이 발생하는 경우ObjectOptimisticLockingFailureException
예외가 발생하고 이를 애플리케이션 단에서 처리해줘야 한다.
비관적 락 < 낙관적 락
낙관적 락
은 트랜잭션을 필요로하지 않기 때문에 성능적으로 비관적 락보다 더 좋다.
비관적 락
은 데이터 자체에 락을 걸기 때문에 동시성이 떨어져 성능이 많이 저하되며, 서로의 자원이 필요한 경우에는 데드락이 일어날 가능성도 있다.
하지만 충돌이 많이 발생하는 환경에서는 반대가 된다.
충돌이 발생했을 때, 비관적 락은
트랜잭션을 롤백하면 끝난다. 하지만 낙관적 락은
까다로운 수동 롤백 처리는 둘째 치고, 성능 면에서도 update를 한번씩 더 해줘야 하기 때문에, 비관적 락 보다 좋지 않을 수 있다.
비관적 락을 사용하면 좋은 경우
데이터의 무결성이 중요하다.
데이터 충돌이 많이 발생할 것으로 예상된다.
낙관적 락을 사용하면 좋은 경우
데이터 충돌이 자주 일어나지 않을 것이라고 예상된다.
조회 작업이 많아 동시 접근 성능이 중요하다.