백엔드 관련 강의 공부/동시성 이슈 - 재고시스템

mysql을 활용한 동시성 문제 해결 - 3. Named Lock

chanhee01 2024. 2. 3. 16:55

3. Named Lock

이름을 가진 meta data lock이다. 이름을 가진 lock을 획득하고 해제할 때까지 다른 session은 이 lock을 획득할 수 없다.

트랜잭션이 종료될 때 자동으로 lock이 해제되지 않기 때문에 별도의 명령어로 해제해야만 한다.

 

public interface LockRepository extends JpaRepository<Stock, Long> {
    // 편의를 위해서 Stock 엔티티를 사용하는데, 실무에서는 data source를 분리해서 사용해야 한다.
    // 같은 data source를 사용하면 connection pool이 부족해진다.
    
    @Query(value = "select get_lock(:key, 3000)", nativeQuery = true)
    void getLock(String key);
    
    @Query(value = "select release_lock(:key)", nativeQuery = true)
    void releaseLock(String key);
}

LockRepository를 별도로 만들었다. 실무에서는 이렇게 하면 안되고 별도의 JDBC 등을 사용해야 한다고 한다.

 

 

실제 로직 전, 후로 lock 획득, 해제를 해야하기 때문에 facade class를 추가해준다.

 

 

 

NamedLockStockFacade.class

@Component
@RequiredArgsConstructor
public class NamedLockStockFacade {

    private final LockRepository lockRepository;

    private final StockService stockService;

    @Transactional
    public void decrease(Long id, Long quantity) {
        try {
            lockRepository.getLock(id.toString());
            stockService.decrease(id, quantity);
        } finally {
            lockRepository.releaseLock(id.toString());
        }
    }
}

 

 

 

StockService.class

@Service
@RequiredArgsConstructor
public class StockService {

    private final StockRepository stockRepository;

    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void decrease(Long id, Long quantity) {

        Stock stock = stockRepository.findById(id).orElseThrow();
        stock.decrease(quantity);

        stockRepository.save(stock);
    }
}

StockService를 사용하기 때문에 @Transactional 어노테이션에 propagation을 붙여준다.

 

 

이렇게 변경하고 테스트 코드를 실행해도 정상적으로 성공한다.

 

 

장점

Named lock은 주로 분산 lock을 구현할 때 사용한다. Named lock은 time out을 손쉽게 구현할 수 있다는 장점이 있다.

 

 

단점

트랜잭션 종료 시에 lock 해제, session 관리를 잘 해줘야하며, 실무에서 구현 방법이 다소 복잡할 수 있다.