Pessimistic Lock (비관적 락)
💡Pessimistic Lock (비관적 락) 이란?
https://annovation.tistory.com/509
[동시성 처리] 동시성 문제 (Race Condition) 해결 방법 3가지 관점 (실습중..)
동시성 문제 (Race Condition)💡해결 방법레이스 컨디션을 해결하는 방법에는 크게 3가지 관점이 있다.첫번째는 Java에서 지원하는 Synchronized 방법으로 해결하기두번째는 DB가 제공하는 Lock 을 이용하
annovation.tistory.com
동시성 처리
💡동시성 처리 전 코드
- StockServiceImpl
@Override
@Transactional
public StockResult decreaseStock(StockRequests.Decrease request) {
Product product = getProductOrThrow(request.productId());
Stock stock = getStockOrThrow(request.productId());
stock.decreaseQuantity(request.quantity());
return StockResult.from(stock, product.getName());
}
- Stock
public void decreaseQuantity(int decreaseQuantity) {
validateDecreaseQuantity(decreaseQuantity);
if (this.quantity < decreaseQuantity) {
throw new GlobalException(INSUFFICIENT_STOCK);
}
this.quantity -= decreaseQuantity;
}
- JpaStockRepository
public interface JpaStockRepository extends JpaRepository<Stock, UUID> {
Optional<Stock> findByProductId(UUID productId);
}
- StockRepository
public interface StockRepository {
Stock save(Stock stock);
Optional<Stock> findByProductId(UUID productId);
}
- StockRepositoryAdapter
@Repository
@RequiredArgsConstructor
public class StockRepositoryAdapter implements StockRepository {
private final JpaStockRepository jpaStockRepository;
@Override
public Stock save(Stock stock) {
return jpaStockRepository.save(stock);
}
@Override
public Optional<Stock> findByProductId(UUID productId) {
return jpaStockRepository.findByProductId(productId);
}
}
💡동시성 처리 전 테스트 코드 결과

- 재고 100개에 대해 1개씩 100번 동시 차감했을 때 0이 되어야 하는데, 실제로는 88이 남아 동시성 제어가 제대로 되지 않아 일부 차감이 반영되지 않은 상태에서 발생한 AssertionFailedError가 발생했다.
💡동시성 처리 한 코드
- JpaStockRepository
public interface JpaStockRepository extends JpaRepository<Stock, UUID> {
Optional<Stock> findByProductId(UUID productId);
@Lock(LockModeType.PESSIMISTIC_WRITE)
@Query("select s from Stock s where s.productId = :productId")
Optional<Stock> findByProductIdForUpdate(@Param("productId") UUID productId);
}
➡️ @Lock(PESSIMISTIC_WRITE)가 붙어서 실행 시점에 FOR UPDATE가 추가된다.
- StockRepository
public interface StockRepository {
Stock save(Stock stock);
Optional<Stock> findByProductId(UUID productId);
Optional<Stock> findByProductIdForUpdate(UUID productId);
}
- StockRepositoryAdapter
@Repository
@RequiredArgsConstructor
public class StockRepositoryAdapter implements StockRepository {
private final JpaStockRepository jpaStockRepository;
@Override
public Stock save(Stock stock) {
return jpaStockRepository.save(stock);
}
@Override
public Optional<Stock> findByProductId(UUID productId) {
return jpaStockRepository.findByProductId(productId);
}
@Override
public Optional<Stock> findByProductIdForUpdate(UUID productId) {
return jpaStockRepository.findByProductIdForUpdate(productId);
}
}
- StockServiceImpl
private Stock getStockForUpdateOrThrow(UUID productId) {
return stockRepository.findByProductIdForUpdate(productId)
.orElseThrow(() -> new GlobalException(STOCK_NOT_FOUND));
}
➡️ Lock 조회 메서드 추가
💡동시성 처리 후 테스트 코드 결과

- 테스트가 성공적으로 통과되었다 !
'Projects > HubEleven' 카테고리의 다른 글
| [동시성 처리] DB Lock : Optimistic Lock (낙관적 락) - 실습 (0) | 2026.02.20 |
|---|---|
| [동시성 처리] Trouble Shooting : Pessimistic Lock 적용 오류 (0) | 2026.02.19 |
| [동시성 처리] Trouble Shooting : 멀티스레드 재고 감소 통합 테스트 코드 Eureka Server Connection refused (0) | 2026.02.16 |
| [동시성 처리] synchronized vs Reentrant Lock - 실습 (0) | 2026.02.15 |
| [동시성 처리] JVM Lock : synchronized VS Reentrant Lock (실습중..) (0) | 2026.02.14 |