예제


01:00 ⇒ 이름 가명화 ETL 동작

SELECT NAME
FROM PATIENT
WHERE ID = 'evan';

결과

01:00 ⇒ 홍길동

01:01 ⇒ 홍**

데이터의 정합성 어긋나는 현상 발생!

문제 해결#1 - Application Level


원본 StockService

@Service
@RequiredArgsConstructor
public class StockService {

    private final StockRepository stockRepository;

    public void decrease(Long id, Long quantity) {
        // get stock
        Stock stock = stockRepository.findById(id).orElseThrow();

        // 재고 감소
        stock.decrease(quantity);

        // 저장
        stockRepository.saveAndFlush(stock);
    }

}

Test

@DisplayName("동시 요청 테스트")
@Test
public void concurrency() throws InterruptedException {
    int threadCount = 100;
    ExecutorService executorService = Executors.newFixedThreadPool(32);
    CountDownLatch latch = new CountDownLatch(threadCount);

		for (int i = 0; i < threadCount; i++) {
		    executorService.submit(() -> {
		        try {
		            stockService.decrease(1L, 1L);
		        } finally {
		            latch.countDown();
		        }
		    });
    }

    latch.await();

    Stock stock = stockRepository.findById(1L).orElseThrow();

    // 100 - (1 * 100) = 0
    assertEquals(0L, stock.getQuantity()); // **오류 발생!**
}

Race Condition 발생!

둘 이상의 스레드가 공유 데이터에 엑세스할 수 있고 동시에 변경하려고 할 때 발생하는 문제

하나의 스레드만 데이터에 엑세스할 수 있도록 해야한다!

개선된 StockService

@Service
@RequiredArgsConstructor
public class StockService {

    private final StockRepository stockRepository;

    public **synchronized** void decrease(Long id, Long quantity) {
        // get stock
        Stock stock = stockRepository.findById(id).orElseThrow();

        // 재고 감소
        stock.decrease(quantity);

        // 저장
        stockRepository.saveAndFlush(stock);
    }

}