둘 이상의 Thread 가 공유 자원에 접근해서 동시에 변경을 할 때 발생하는 문제
synchronized 키워드가 붙은 메서드에 하나의 스레드만 접근이 가능하도록 만듦
@Transactional
public synchronized void decrease(final Long id, final Long quantity) {
final Stock stock = stockRepository.findById(id).orElseThrow();
stock.update(quantity);
stockRepository.saveAndFlush(stock);
}
정확한 동시성 제어가 이루어지지 않음
@Transactional 이 붙은 메서드는 Proxy 객체를 생성하여 트랜잭션 관련 처리를 수행
메서드 내부의 DB 변경 내용이 DB 에 반영되는 시점은 트랜잭션이 커밋되고 종료되는 시점
즉, 변경 내용이 DB 에 반영되기 이전에, 다른 스레드에서 해당 메서드를 실행시킨 상황이라면
이후, 변경 내용이 반영되지 않은 DB 에 대하여 조회 및 수정이 일어난다.
예상한 쿼리가 실행되지 않을 수 있다. Ex. UPDATE 문이 여러번 실행되어야 하지만, 마지막에 한번만 실행된다.
또 다른 문제점
이러한 이유로, 실무에서는 동시성을 해결하는 방법으로 synchronized 는 거의 사용하지 않는다.
Shared Lock (공유 잠금, S Lock)
특정 Row를 읽을(read) 때 사용되어지는 Lock
특징
쿼리
SELECT * FROM what FOR SHARE
Exclusive Lock (배타 잠금, X Lock)
특정 Row를 변경(write) 할때 사용되어지는 Lock
특징
쿼리
SELECT * FROM what FOR UPDATE
Record Lock, Gap Lock, Next-Key Lock 등의 Lock 도 존재한다.