- 동시에 여러개의 요청이 들어오면 어떻게 될까?
- 실패를 하게 된다
- 레이스 컨디션이 일어났기때문
- 둘 이상 스레드가 공유 데이터에 엑세스할 수 있고
- 동시에 변경을 하려고 할때 발생하는 문제때문.
- 갱신되기 전에 값을 가져가서 둘다 100에서 1을 빼기 때문에
- 갱신이 누락된다.
- 하나 스레드가 작업이 완료후 다른 스레드가 작업 완료되게 하자
Synchronized
- 트랜잭션 애노테이션 동작방식 때문에 실패함
- 스프링에서는 우리가 만든클래스를 래핑할 클래스를 새로만들어서 실행함.
- 스탁서비스를 필드로가지는 클래스를 새로만들어서 실행함
- 트랜잭션 시작한후 메소드호출하고 메소드 실행이 종료하게된다면
- 트랜잭션을 종료하게 됨.
- 여기서 문제!
- 트랜잭션 종료시점에 데이터베이스를 업데이트하지만
- 디크리스 메소드가 완료되기전에 다른 스레드가 디크리스 메서드를 호출 할수 있다.
- 그런다면 다른 스레드는 갱신되기전 값을 가져가서 동일한 문제가 발생함
- 자바의 synchronized는 하나의 프로세스 안에서만 보장 됨
- 서버가 2대 그 이상일 경우 데이터 접근이 여러대에서 할 수 있게 됨
- 이런식으로 갱신되지 않는 값을 들어가서 새롭게 다시 갱신된다.
- 싱크로나이즈드는 각 프로세스 안에서만 보장되기 때문에
- 결국 여러 스레드에서 동시에 데이터 접근이 가능해서 레이스 컨디션이 발생하게 됨
- 실제 운영중인 서비스는 2대이상이기 때문에 싱크로나이즈드는 사용하지 않는다.
Mysql
Pessimistic Lock
- 서버1이 락을 걸면 나머지는 들어가지 못함
- 실제로 데이터의 락을 걸어서 데이터 정합성을 맞춤
- 이렇게 작성하고
- service를 바꿔준뒤 아까 작성한 테스트를 실행하면
장점
- 충돌이 빈번하게 일어나면? 옵티미스팅 락보다 성능이 좋다
- 데이터 정합성이 보장됨
- 별도의 락으로 인한 성능 감소
Optimistic Lock
- 내가 읽은 버전에서 수정사항이 생겼을 경우 어플리케이션에서 다시 읽은후 수정
- 업데이트 수행하게되면 where 절에 version 조건이 들어감
- 동시에 버전이 올라감
- 버전이 틀리면 수정 실패
- 이 부분은 @Version 어노테이션만 추가하면됨
- 재시도 로직이 있어서 좀 더 걸리지만 성공
- 비관적 잠금보다 성능이 우수
- 재시도 로직 작성해 줘야됨 -> 단점
- 충돌이 그리 심하지않으면 낙관적락을 사용하는게좋음
Named Lock
- 이름을 가진 락
- 이름을 가진 락을 획득후 해제할때까지 다른 세션은 접근을 못함
- 트랜잭션이 끝나도 해제가 안돼서 별도 수동으로 입력하거나 시간이 지나야된다.
- 메타데이터의 락킹 방법
- 별도 공간에 락을 검
- 세션 1이 1이라는 이름으로 락을 거면
- 세션 1 이 종료하고 세션2가 접근 가능함
- 실무에서는 데이터소스를 분리해서 사용해야된다
- 이번 예제는 분리하지 않음
- 락 획득후 재고 감소
- 모든 로직 종료시 락 해지
- 부모의 트랜지션과 별도로 실행되어야 되서 프로게이션 변경
- 같은 데이터소스를 사용하기 때문에 넉넉하게 40
- 테스트는 성공
- 주로 분산락 구현할때 사용하는
- 타임아웃 손쉽게 구현(비관적락은 구현하기 어렵다)
- 데이터 삽입시 정합성 맞춰야 하는경우 사용한다.
- 락 해제 세션 관리를 해줘야하고 구현방법이 복잡할 수 있다.