Skip to the content.

LockQueryAdapter 가이드

목적: Lock을 걸고 조회하는 CQRS Query Adapter 구현 가이드 (1:1 매핑)


1️⃣ LockQueryAdapter란?

역할

Lock Query 요청 → LockRepository → Entity → Mapper → Domain 반환

Lock을 걸고 조회하는 Query(읽기) 담당으로, LockRepository에 1:1 매핑되어 위임하고 Mapper를 통해 Domain으로 변환하여 반환합니다.

책임

핵심 원칙

Application Layer (UseCase)
  └─ Lock Query Port 호출
      └─ LockQueryAdapter (1:1 매핑)
            └─ LockRepository
                  └─ DB Lock 조회

2️⃣ 핵심 원칙

원칙 1: 1:1 매핑

원칙 2: Lock 조회만 담당

원칙 3: LockRepository 위임 + Mapper 변환

// ✅ LockRepository 호출 → Mapper 변환 → Domain 반환
public Optional<Bc> findByIdForUpdate(BcId id) {
    return lockRepository.findByIdForUpdate(id.getValue())
        .map(bcJpaEntityMapper::toDomain);
}

// ❌ 비즈니스 로직 금지
public Optional<Bc> findByIdForUpdate(BcId id) {
    Optional<Bc> bc = lockRepository.findByIdForUpdate(id.getValue())
        .map(bcJpaEntityMapper::toDomain);

    if (bc.isPresent() && bc.get().isExpired()) {  // 금지!
        return Optional.empty();
    }
    return bc;
}

원칙 4: Type-Safe Value Objects

// ✅ Value Object 사용 (타입 안전성)
public Optional<Bc> findByIdForUpdate(BcId id) {
    return lockRepository.findByIdForUpdate(id.getValue())
        .map(bcJpaEntityMapper::toDomain);
}

// ❌ 원시 타입 사용 금지
public Optional<Bc> findByIdForUpdate(Long id) {  // 금지!
}

원칙 5: 6개 메서드 고정 (통일된 네이밍)

Lock 유형 단건 조회 목록 조회 SQL
Pessimistic Write findByIdForUpdate findByCriteriaForUpdate SELECT … FOR UPDATE
Pessimistic Read findByIdForShare findByCriteriaForShare SELECT … FOR SHARE
Optimistic findByIdWithOptimisticLock findByCriteriaWithOptimisticLock @Version 사용

원칙 6: Lock 예외 명시 (JavaDoc)

// ✅ JavaDoc에 @throws 명시 (처리는 안 함)
/**
 * ID로 Bc 단건 조회 (FOR UPDATE)
 *
 * @param id Bc ID
 * @return Bc Domain (Optional)
 * @throws PessimisticLockException Lock 획득 실패 시
 * @throws LockTimeoutException Lock 타임아웃 시
 */
public Optional<Bc> findByIdForUpdate(BcId id) {
    // 예외를 catch하지 않고 그대로 던짐
    return lockRepository.findByIdForUpdate(id.getValue())
        .map(bcJpaEntityMapper::toDomain);
}

// ❌ try-catch로 예외 처리 금지 (Application Layer에서 처리)
public Optional<Bc> findByIdForUpdate(BcId id) {
    try {
        return lockRepository.findByIdForUpdate(id.getValue())
            .map(bcJpaEntityMapper::toDomain);
    } catch (PessimisticLockException e) {  // 금지!
        throw new CustomLockException(e);
    }
}

예외 처리 책임:


3️⃣ 템플릿 코드

Port 인터페이스

public interface {Bc}LockQueryPort {

    // Pessimistic Write Lock (FOR UPDATE)
    Optional<Bc> findByIdForUpdate({Bc}Id id);
    List<Bc> findByCriteriaForUpdate({Bc}SearchCriteria criteria);

    // Pessimistic Read Lock (FOR SHARE)
    Optional<Bc> findByIdForShare({Bc}Id id);
    List<Bc> findByCriteriaForShare({Bc}SearchCriteria criteria);

    // Optimistic Lock (@Version)
    Optional<Bc> findByIdWithOptimisticLock({Bc}Id id);
    List<Bc> findByCriteriaWithOptimisticLock({Bc}SearchCriteria criteria);
}

Adapter 구현

@Component
public class {Bc}LockQueryAdapter implements {Bc}LockQueryPort {

    private final {Bc}LockRepository lockRepository;
    private final {Bc}JpaEntityMapper {bc}JpaEntityMapper;

    public {Bc}LockQueryAdapter(
        {Bc}LockRepository lockRepository,
        {Bc}JpaEntityMapper {bc}JpaEntityMapper
    ) {
        this.lockRepository = lockRepository;
        this.{bc}JpaEntityMapper = {bc}JpaEntityMapper;
    }

    // ========================================================================
    // Pessimistic Write Lock (FOR UPDATE)
    // ========================================================================

    /**
     * ID로 Bc 단건 조회 (FOR UPDATE)
     *
     * @param id Bc ID
     * @return Bc Domain (Optional)
     * @throws PessimisticLockException Lock 획득 실패 시
     * @throws LockTimeoutException Lock 타임아웃 시
     */
    @Override
    public Optional<Bc> findByIdForUpdate({Bc}Id id) {
        return lockRepository.findByIdForUpdate(id.getValue())
            .map({bc}JpaEntityMapper::toDomain);
    }

    /**
     * Criteria로 Bc 목록 조회 (FOR UPDATE)
     *
     * @param criteria 검색 조건
     * @return Bc Domain 목록
     * @throws PessimisticLockException Lock 획득 실패 시
     * @throws LockTimeoutException Lock 타임아웃 시
     */
    @Override
    public List<Bc> findByCriteriaForUpdate({Bc}SearchCriteria criteria) {
        List<{Bc}JpaEntity> entities = lockRepository.findByCriteriaForUpdate(criteria);
        return entities.stream()
            .map({bc}JpaEntityMapper::toDomain)
            .toList();
    }

    // ========================================================================
    // Pessimistic Read Lock (FOR SHARE)
    // ========================================================================

    /**
     * ID로 Bc 단건 조회 (FOR SHARE)
     *
     * @param id Bc ID
     * @return Bc Domain (Optional)
     * @throws PessimisticLockException Lock 획득 실패 시
     * @throws LockTimeoutException Lock 타임아웃 시
     */
    @Override
    public Optional<Bc> findByIdForShare({Bc}Id id) {
        return lockRepository.findByIdForShare(id.getValue())
            .map({bc}JpaEntityMapper::toDomain);
    }

    /**
     * Criteria로 Bc 목록 조회 (FOR SHARE)
     *
     * @param criteria 검색 조건
     * @return Bc Domain 목록
     * @throws PessimisticLockException Lock 획득 실패 시
     * @throws LockTimeoutException Lock 타임아웃 시
     */
    @Override
    public List<Bc> findByCriteriaForShare({Bc}SearchCriteria criteria) {
        List<{Bc}JpaEntity> entities = lockRepository.findByCriteriaForShare(criteria);
        return entities.stream()
            .map({bc}JpaEntityMapper::toDomain)
            .toList();
    }

    // ========================================================================
    // Optimistic Lock (@Version)
    // ========================================================================

    /**
     * ID로 Bc 단건 조회 (Optimistic Lock)
     *
     * <p>조회 시 Lock을 걸지 않으며, 업데이트 시 OptimisticLockException 발생 가능</p>
     *
     * @param id Bc ID
     * @return Bc Domain (Optional)
     */
    @Override
    public Optional<Bc> findByIdWithOptimisticLock({Bc}Id id) {
        return lockRepository.findByIdWithOptimisticLock(id.getValue())
            .map({bc}JpaEntityMapper::toDomain);
    }

    /**
     * Criteria로 Bc 목록 조회 (Optimistic Lock)
     *
     * <p>조회 시 Lock을 걸지 않으며, 업데이트 시 OptimisticLockException 발생 가능</p>
     *
     * @param criteria 검색 조건
     * @return Bc Domain 목록
     */
    @Override
    public List<Bc> findByCriteriaWithOptimisticLock({Bc}SearchCriteria criteria) {
        List<{Bc}JpaEntity> entities = lockRepository.findByCriteriaWithOptimisticLock(criteria);
        return entities.stream()
            .map({bc}JpaEntityMapper::toDomain)
            .toList();
    }
}

4️⃣ 체크리스트

LockQueryAdapter 구현 시:

구조

6개 메서드 (통일된 네이밍)

예외 처리

금지 사항


작성자: Development Team 최종 수정일: 2025-11-12 버전: 1.0.0