작성
·
1.1K
0
안녕하세요 재고관리시스템 강의를 복습하며 내용을 정리하는 중 의문이 생겨 질문을 드립니다.
가장 처음에 application code 레벨에서만 동시성을 해결하기 위해 syncrhonized 를 사용할 경우 해당 메서드에는 @Transactional 을 붙여서는 안된다고 설명해 주셨습니다.
실제로 이를 붙일 경우, 동시에 decrease 메서드가 호출되고 해당 로직 내부로 들어가는 것이 가능함을 확인하였습니다.
그런데 여기서 제가 의문이 들었던 것이 있습니다.
@Transacitonal 을 사용할 경우 Spring AOP 에 의해 매 번 다른 proxy 인스턴스를 통해 target object 로의 호출을 하게 됩니다.
proxy 객체에 대한 lock 은 서로 다른 프록시들 사이에 공유되지 않는다고 하더라도, 내부적으로 호출되는 target 객체에 대한 decrease 메서드는 결국 동일한 객체에 대한 호출을 하기 때문에, 공유되는 lock 에 대한 경쟁이 일어나는 것이 아닌가 생각이 들었습니다.
최종적으로는 target 객체에 대한 synchronized 메서드를 호출하는 것이라면, 단 하나의 스레드만 임계 영역에 들어갈 수 있어야 할 것 같은데, 그렇지 않음을 확인하였습니다.
왜 이런 일이 일어나는 것인지 이해가 잘 되지 않습니다 ㅠㅠ
이와 관련해서 어떤 키워드로 공부해보면 좋을지 추천 가능할까요..?
답변 2
1
스빈스빈별님 안녕하세요.
syncrhonized 메소드에 Transactional 을 붙이게 된다면 아래와 같은 순서로 동작하게 될 것입니다.
class DemoServiceProxy {
DemoService demoService;
public void demo() {
try {
transaction.start()
demoService.decrease()
} catch(Exception e){
transaction.rollback()
} finally {
transaction.commit()
}
}
}
class DemoService {
synchronized public void decrease() {
// 수량 감소
}
}
이렇게 동작할때 demoService 의 decrease 메소드가 모두 동작되고 트랜잭션이 커밋할때까지 잠깐의 텀이 발생하게 됩니다. 이 텀 사이에 다른 스레드가 demoService 의 decrease 에 접근할 수 있게되고 그로인해 문제가 발생하게 됩니다.
그림으로 그려보면서 차근차근 따라가보시면 도움이 되실 것 같습니다.
감사합니다.
0
안녕하세요. 제가 이해한게 맞는지 궁금해서 여쭤봅니다.
@Transactional에서 고립 레벨 디폴트가 read_committed 이고, synchronized는 quantity를 동기화할 뿐, 트랜잭션의 시작과 끝을 동기회하지는 않음.
그래서 여러 스레드에서 트랜잭션이 동시에 시작되고, 모든 트랜잭션들이 자신의 트랜잭션이 시작되기 전에 커밋된 quantity == 100개의 상태일 때 접근하게 됨. (
read_committed이면 다른트랜잭션이 커밋한 내용이 보이는데,아직 다들 커밋을 안한 상태라서 현재 모두들 공유자원이 100개로 보이는 상태.)
이 순간에 quantity가 동기화되면서 하나의 스레드씩만 접근을 해서 quantity를 줄이고, 그 quantity에 대한 락이 풀림. 그리고 먼저 실행된 트랜잭션이 커밋되려고 하는데, 다른 트랜잭션이 그때 락이 풀려있는 quantity에 접근할 수 있음.
위 내용대로 이해했는데 맞을까요?