인프런 커뮤니티 질문&답변

아리마님의 프로필 이미지
아리마

작성한 질문수

재고시스템으로 알아보는 동시성이슈 해결방법

synchronized 문의

작성

·

333

0

안녕하세요.

강의에서는 트랜잭션이 필요한 곳에서 @Transactional 어노테이션을 적용하게 되면 synchronized 를 사용해도

올바른 결과가 나오지 못함을 설명해주셨는데요. 그래서 @Transactional 을 제외시키고 synchronized 를 적용해서

테스트를 돌리셨습니다. 이후 끝맺음이 다소 부족했던 것 같은데요.

그래서 결과적으로 트랜잭션 AOP 를 적용하는 곳에서는 syncronized 는 무쓸모한 옵션이다라는 말씀일까요?

트랜잭션 내에서 해당 기능을 사용할 수 있는 방법같은 건 없는 것인지요?  

답변 4

0

@Transactional(isolation = Isolation.SERIALIZABLE)
public void decrease(Long id, Long quantity) {
    Stock stock = stockRepository.findById(id).orElseThrow();
    stock.decrease(quantity);
    stockRepository.saveAndFlush(stock);
}

안녕하세요. MySQL InnoDB의 default level은 repeatable_read로 알고 있어서 한 단계 더 높은 수준인 serializable로 설정하면 동시성 이슈를 해결할 수 있을거라 생각을 했었는데요. 그래도 동시성 이슈가 발생하더라구요..

제가 뭘 놓치고 있을까요?

0

예제에서 들어주신 것처럼 @Transactional을 선언한 메서드와 sycronize로 선언한 메서드를 분리한 서비스를 각각 만들어서 사용하는 경우, 어떤 장점이 있나요?

실무에서는 syncronize를 사용하지 않는다고 하셨는데, 위의 예제와 같이 사용하는 경우는 어떤 경우인지 궁금합니다.

 

최상용님의 프로필 이미지
최상용
지식공유자

slr과르님 안녕하세요 :)

첫번째 질문에 때한 답변입니다.

Synchronized 를 선언한 메소드안에서 @Transactional 어노테이션이 붙은 메소드를 호출하게 된다면, 트랜잭션이 모두 종료되고 커밋할때까지 Synchronized 가 보장됩니다.
그렇기때문에 영상에서 발생되는 문제는 발생되지 않을겁니다.
다만, 기존의문제와 마찬가지로 2개 이상의 서버를 사용하게 된다면 동일한 문제가 발생됩니다.

 

 

두번째 질문에 대한 답변입니다.

실무에서는 보통 2대 이상의 서버를 운용합니다. 서버를 1대로만 서비스를 운용하게 된다면 서버가 다운됐을때 서비스를 이용할 수 없게되기 때문에 서버를 2대 이상 운용함으로써 서버가 1대 다운되더라도 다른서버로 요청을 보냄으로써 서비스를 끊기지 않고 운영할 수 있게 합니다.

Synchronized 는 2대이상의 서버를 사용할 때 문제가 발생할 수 있으므로 실무에서는 거의 사용되지 않습니다.

사용되는 경우는 서버가 1대로만 운영이 되거나, 서버내에서만 정합성이 보장되면 될 때 사용됩니다.

말도 안되는 예제이지 10대의 서버가 있고, 1대의 서버마다 100개의 쿠폰만 발행한다고 가정해봅시다.
이럴때는 서버내에서만 정합성이 보장되면 되므로 Synchronized 를 활용하여 개발할 수 있을듯합니다.

0

아리마님의 프로필 이미지
아리마
질문자

네, 잘 배웠습니다. 상세한 답변 감사드립니다.

0

최상용님의 프로필 이미지
최상용
지식공유자

안녕하세요. 아리마님.

syncronized 는 서버가 2대 이상일때 정합성을 보장해주지 못합니다.

그렇기때문에 정합성을 맞추기 위해서 실무에서는 거의 사용되지 않는다고 할 수 있습니다.

트랜잭션 내에서 해당 기능을 사용한다면 영상에서 보이는 문제가 발생하므로 권장하지 않습니다.

 

@Transactional 어노테이션과 syncronized 를 함께 사용하고 싶으시다면  이런식으로 사용할 수 있을듯 합니다.

@Service
public class DemoStockService {

    @Transactional
    public void decrease(Long id, Long quantity) {
        // TODO
    }
}

 

@Component
public class DemoClass {

    private final DemoStockService demoStockService;

    public DemoClass(DemoStockService demoStockService) {
        this.demoStockService = demoStockService;
    }

    public synchronized void decrease(Long id, Long quantity) {
        demoStockService.decrease(id, quantity);
    }
}
아리마님의 프로필 이미지
아리마

작성한 질문수

질문하기