JPA나 다른 DB 기술로 개발할 때, 데이터 정확성 & 성능은 놓칠 수 없는 두마리의 토끼이다.
하지만 자동차를 생각해보면 속도를 빠르게 할 수록 운전자의 안전성은 낮아지지만, 속도가 느리다면 오히려 운전자의 안전성의 높아지는 상황처럼 두마리 토끼를 다 가져가기란 DB에서도 어려운 일이다.
즉 우리는 애플리케이션의 상황에 따라 적절한 락을 사용하여 문제를 해결해야한다.
비관적 락 (Pessimistic Locking)
비관적 락의 개념

비관적 락은 박명수라고 생각하자. -> 충돌이 반드시 일어날거니까 미리 막자!
이름처럼 비관적 락은 어느 한 트랜잭션이 데이터를 동시에 수정할 것이라고 비관적으로 가정하고 데이터를 읽는 순간 그 로우에 아예 락을 걸어버려 다른 트랜잭션의 접근을 막는 방식이다.
즉, 데이터 정합성이 100% 보장되는 방식이다.
예시 상황
1. 트랜잭션 A가 데이터 변경을 위해 DB 엔티티의 로우에 접근을 시도한다.
2. 이때, 해당 테이블에 접근한 트랜잭션이 없다면 해당 로우의 락을 획득하고 다른 트랜잭션의 접근을 막는다.
3. 트랜잭션 B가 같은 로우에 접근을 시도한다.
4. 이미 A가 해당 로우를 사용하고 있기 때문에, B는 A가 작업을 마칠 때까지 WAIT 하거나 설정 시간만큼 지나게 되면 작업을 포기하고 예외를 발생시킨다.
5. A가 작업을 마치고(커밋 혹은 롤백) 락을 반납하면 WAIT 하고 있던 B가 해당 락을 다시 획득하여 1번 단계로 넘어가 반복한다.
장점 및 단점
비관적 락 방식은 동시성 문제 해결이 가장 확실하고 코드 작성시 구현이 비교적 단순하다.
하지만 단점은 하나의 트랜잭션이 만약 전체 범위의 테이블이 필요한게 아니라 해당 로우나 컬럼에 접근이 필요한데 테이블 전체에 대한 락을 가져가 버리면, 해당 트랜잭션의 작업이 커밋 또는 롤백 되기 전까지 다른 트랜잭션의 접근이 원천 차단 되므로 성능 병목 현상(Turtle neck)이 심각해지고 처리량이 구려질 수 있다.
낙관적 락 (Optimistic Locking)
낙관적락의 개념

낙관적 락은 비관적 락과 반대되는 개념이다. 유재석 락이라고 생각하자. -> 충돌하더라도 일단 진행하고 나중에 잘못 되면 확인하자 !
낙관적락은 서로 다른 트랜잭션이 데이터를 동시에 수정하지 않을 것이라고 낙관적으로 가정하고 일단 모든작업을 처리한다. 이후 데이터를 실제로 커밋하려고 할 때 충돌여부를 검사하는 방식이다.
이는 DB의 병목현상을 줄이고 높은 동시 처리량을 확보할 수 있는 방법이다.
낙관적 락 방식 사용시 반드시 해당 락의 변경 유무를 확인하기 위한 방법이 필요하다.
대표적으로는 Version 컬럼등을 설정하여 데이터가 변경 되었는지 확인 하는 방식이 있다.
예시 상황
1. 트랜잭션 A가 데이터를 변경하기 위해 특정 로우에 접근한다.
2. 이때 트래잭션 A는 락을 따로 걸지 않고 해당 로우의 현재 데이터를 읽는다. (이때 Version 컬럼의 값은 1)
3. 트랜잭션 B가 해당 로우에 접근을 시도한다. B 또한 따로 락을 걸지 않고 해당 로우의 현재 데이터와 Version 컬럼의 정보를 같이 읽어온다. (이때도 아직 A가 작업중이기 때문에 B도 Version 의 값을 1로 읽어온다)
4. A가 먼저 작업을 마친 후 커밋을 시도한다.
이때 현재 DB의 Version 컬럼 데이터와 A가 작업한 데이터의 버전 정보가 같다면 그 사이에 수정된 이력이 없다고 판단하고 데이터 수정후 Version의 값을 Version의 기존 값 + 1로 변경한다 (1이었으면 2로 변경)
5. 이제 B도 작업을 마치고 커밋을 시도한다. 이때 B는 Version = 1 이라는 데이터를 가지고 있다.
이때 B가 커밋 시도시 현재 해당 로우의 Version은 A가 2로 바꿔놓았기 때문에, 데이터가 변경되었다는 것을 감지하고, 작업했던 내용을 롤백한 뒤 현재 데이터를 기준으로 다시 작업을 시도한다.
6. 일정 작업시도 횟수를 초과하게 되면 낙관적 락에 대한 예외를 발생시키며 롤백된다.
장점 및 단점
락이 없으므로 읽기 성능이 매우 좋고, DB 자원을 거의 사용하지 않는다.
하지만 충돌이 발생하게 되면 반드시 재시도 로직이 필요하고, 충돌이 잦은 환경에서는 오히려 재시도 비용이 더 크게 적용되어 비효율적일 수 있다.