데이터베이스에서 동시성 문제를 해결하는 방법을 알아보자!
데이터베이스에서 값을 변경하는 일은 다음 세 가지 단계로 진행된다.
1. 데이터베이스에서 값을 읽어온다. (ray의 현재 잔액은 1000원)
2. 연산을 수행한다. (200원 입금 -> 총액은 1000 + 200 = 1200원)
3. 연산 결과를 저장한다 (1200원 을 데이터베이스에 입력)
만약 1~3 과정 중 중간에 데이터베이스의 값이 변경된다면(ex: 1000 -> 500원), 실제와 다른 값이 최종 결과로 저장된다. (내 실제 계좌는 700원이어야 하는데, 1200원이 된다??!? 없는 돈이 생긴다!)
따라서 1~3의 과정은 "하나의 단위"로써 보장되어야 한다. 데이터베이스에서는 이러한 작업을 보장하기 위해 Lock을 이용한다.
낙관적 락은 일반적으로 층돌이 일어나지 않을 것이라고 보고 작업을 수행하는 것을 말한다.
우선 작업을 수행한 뒤, 작업에 문제가 없는지 확인 후 데이터베이스에 저장한다.
(멀티스레딩에서의 CAS(Compare And Set) 알고리즘과 유사하다)
낙관적 : 데이터 갱신 시 충돌이 발생하지 않을 것이라고 보는 것
비선점적 : 우선적으로 락을 걸지 않고 진행
어플리케이션 락을 통한 충돌 방지
장점
단점
비관적 락은 층돌이 일어날 것을 미리 방지하기 위해 다른 사람들이 데이터에 접근하지 못하도록 막는다.
@Entity
public class MyEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private String id;
private String name;
@Version
private Integer version;
}
OptimisticLockException
예외가 발생한다.// 1. 어노테이션 이용하기
@Lock(LockModeType.OPTIMISTIC)
Optional<MyEntity> findById(Long id);
// 2. entityManager 파라미터 이용하기
em.find(MyEntity.class, id, LockModeType.OPTIMISTIC);
// 1. 어노테이션 이용하기
@Lock(LockModeType.OPTIMISTIC_FORCE_INCREMENT)
Optional<MyEntity> findById(Long id);
// 2. entityManager 파라미터 이용하기
em.find(MyEntity.class, id, LockModeType.OPTIMISTIC_FORCE_INCREMENT);
@Lock(value = LockModeType.PESSIMISTIC_WRITE)
)// 1. Repository에서 어노테이션
@Lock(LockModeType.PESSIMISTIC_WRITE)
Optional<MyEntity> findById(Long id);
// 2. 트랜잭션에 붙이기
@Transactional
@Lock(value = LockModeType.PESSIMISTIC_WRITE)
public ResponseDto myServiceMethod(...)
이때 mysql에서는 다음과 같은 동작이 일어난다
SELECT * FROM my_entity WHERE id = 1 FOR UPDATE;
@Lock(value = LockModeType.PESSIMISTIC_READ)
)// 1. Repository에서 어노테이션
@Lock(LockModeType.PESSIMISTIC_READ)
Optional<MyEntity> findById(Long id);
// 2. 트랜잭션에 붙이기
@Transactional
@Lock(value = LockModeType.PESSIMISTIC_READ)
public ResponseDto myServiceMethod(...)
이때 mysql에서는 다음과 같은 동작이 일어난다
SELECT * FROM my_entity WHERE id = 1 FOR SHARE;
https://hudi.blog/jpa-concurrency-control-optimistic-lock-and-pessimistic-lock/
https://velog.io/@msung99/JPA-%EB%82%99%EA%B4%80%EC%A0%81-%EB%9D%BDOptimistic-Lock-%EA%B3%BC-%EB%B9%84%EA%B4%80%EC%A0%81-%EB%9D%BDPessimistic-Lock-%EC%9D%84-%ED%86%B5%ED%95%9C-%EB%8F%99%EC%8B%9C%EC%84%B1-%EC%9D%B4%EC%8A%88-%ED%95%B4%EA%B2%B0
https://velog.io/@msung99/JPA-%EC%9D%98-%EB%B9%84%EA%B4%80%EC%A0%81-%EB%9D%BD%EC%97%90-%EB%8C%80%ED%95%9C-LockModeType-%EA%B3%B5%EC%9C%A0-%EB%9D%BD%EA%B3%BC-%EB%B0%B0%ED%83%80-%EB%9D%BD