해결된 질문
작성
·
523
1
먼저 좋은 강의 감사드립니다.
프록시 객체에서 이해가 안 가는 부분이 있어 질문드립니다.
@Transactional을 사용하면 프록시 방식의 AOP로 동작하는 것은 이해하고 있습니다.
스프링 부트는 CGLIB 방식으로 프록시 객체를 생성하므로, StockService를 상속하는 StockServiceProxy가 만들어질 때 StockServiceProxy.decrease()에도 synchronized
키워드가 붙어있을 것이라고 생각했습니다.
그런데 강사님께서 TransactionStockService
를 예로 드실 때 synchronized
를 안 붙이신 걸 보니 프록시 객체가 생성될 때는 synchronized
가 안 붙는 건가? 라고 생각들었습니다.
Q. 프록시 객체가 생성될 때 synchronized
없이 메서드가 생성되는 것이 맞을까요?
읽어주셔서 감사합니다 :)
답변 1
1
HRO 님 안녕하세요.
프록시 객체가 생성될때는 synchronized 가 붙여진채로 생성이 됩니다.
TransactionStockService 는 StockService 의 Proxy 객체를 구현한것이 아니라 Transactional 어노테이션을 붙였을 때 저러한 방법으로 동작한다는 것을 쉽게 말씀드리기 위해 작성한 클래스입니다.
감사합니다.
HRO 님 안녕하세요.
저의 착각으로 전달을 잘못드린것 같습니다.
전달을 드리고자 했던 내용은 "synchronized 를 보장한다" 였습니다!
synchronized 는 구현되지 않는것이 맞으며 아래와 같은 매커니즘으로 동작합니다.
// Proxy class
class TransactionStockService {
private StockService stockService;
public void decrease(Long id, Long quantity) {
try{
tx.start();
stockService.decrease();
} catch (Exception e) {
// ....
} finally {
tx.commit();
}
}
}
// Origin Class
class StockService {
public synchronized void decrease(Long id, Long quantity) {
// ....
}
}
추가적인 질문이 있으시다면 답글 남겨주세요!
감사합니다 :)
강사님 빠른 답변 감사합니다.
조금 오래된 글이지만, synchronized 상속과 관련하여 다음 글을 구글링하였습니다.
위 글에서는 결국
synchronized
는 메서드 시그니처가 아니므로, 오버라이딩 할 때 자동으로 상속되지 않는다고 얘기하고 있습니다.강사님 말씀처럼
synchronized
가 붙여진 채로 생성된다면,StockServiceProxy.decrease()는 다음과 같이 생겼을 걸로 예상됩니다.
만약
synchronized
가 붙여진 채로 생성된다면,tx.commit()
이 호출되고 실제 DB에 커밋되기 전에 다른 스레드가 접근해서 커밋되기 이전의 quantity를 읽어서 갱신 손실 문제가 발생했다고 보면 될까요?강의에서는
stockService.decrease()
만 synchronized의 적용을 받아,stockService.decrease()
와tx.commit()
사이에 다른 스레드가 quantity에 접근하여갱신손실 문제가 일어난 것으로 설명해주셨습니다.
Q1.
synchronized
는 원래 상속이 안 되는데 Proxy 객체 생성 시에만synchronized
가 상속 되는 건가요?Q2. Proxy 객체 생성 시에
synchronized
가 붙여진채로 메서드가 생성된다면, 강의에서TransactionStockService
의stockService.decrease()
와endTransaction
사이에 다른 스레드가 접근하는 것이 아니라endTransaction
이 끝나고 DB 트랜잭션이 커밋되는 사이에 다른 스레드가 접근해서 갱신 손실 문제가 일어날 것 같습니다. 제가 이해한 것이 맞을까요?긴 글 읽어주셔서 감사합니다!