카테고리 없음

querydsl 을 이용한 비관적 lock

jw-backend 2024. 7. 1. 21:35
반응형

QueryDSL을 사용하여 비관적 락(Pessimistic Lock)을 적용할 수 있습니다. 비관적 락을 사용하면 데이터베이스 수준에서 행(row) 단위의 락을 걸어 다른 트랜잭션이 해당 행을 수정하지 못하게 합니다. JPA에서는 비관적 락을 사용하기 위해 LockModeType.PESSIMISTIC_WRITE 또는 LockModeType.PESSIMISTIC_READ를 사용할 수 있습니다.

QueryDSL을 사용하여 비관적 락을 적용하는 방법을 예시를 통해 설명드리겠습니다.

1. 엔티티 클래스

먼저, JPA 엔티티 클래스를 정의합니다.

java

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;

@Entity
public class BankAccount {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String accountNumber;
    private String ownerName;
    private Double balance;

    // Getters and Setters
}

2. Repository 인터페이스

Repository 인터페이스를 정의합니다.

java

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Lock;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;

import javax.persistence.LockModeType;
import java.util.Optional;

public interface BankAccountRepository extends JpaRepository<BankAccount, Long>, CustomBankAccountRepository {

    @Lock(LockModeType.PESSIMISTIC_WRITE)
    @Query("SELECT b FROM BankAccount b WHERE b.id = :id")
    Optional<BankAccount> findByIdWithPessimisticLock(@Param("id") Long id);
}

3. CustomBankAccountRepository 인터페이스

커스텀 리포지토리 인터페이스를 정의합니다.

java

import java.util.Optional;

public interface CustomBankAccountRepository {
    Optional<BankAccount> findByIdWithPessimisticLock(Long id);
}

4. CustomBankAccountRepository 구현 클래스

QueryDSL을 사용하여 비관적 락을 구현합니다.

java

import com.querydsl.jpa.impl.JPAQueryFactory;
import org.springframework.stereotype.Repository;

import javax.persistence.EntityManager;
import javax.persistence.LockModeType;
import javax.persistence.PersistenceContext;
import java.util.Optional;

@Repository
public class CustomBankAccountRepositoryImpl implements CustomBankAccountRepository {

    @PersistenceContext
    private EntityManager entityManager;

    private final JPAQueryFactory queryFactory;

    public CustomBankAccountRepositoryImpl(EntityManager entityManager) {
        this.entityManager = entityManager;
        this.queryFactory = new JPAQueryFactory(entityManager);
    }

    @Override
    public Optional<BankAccount> findByIdWithPessimisticLock(Long id) {
        QBankAccount bankAccount = QBankAccount.bankAccount;
        
        BankAccount result = queryFactory.selectFrom(bankAccount)
                .where(bankAccount.id.eq(id))
                .setLockMode(LockModeType.PESSIMISTIC_WRITE)
                .fetchOne();

        return Optional.ofNullable(result);
    }
}

5. 서비스 클래스

서비스 클래스에서 비관적 락을 사용한 메서드를 호출합니다.

java

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Optional;

@Service
public class BankAccountService {

    @Autowired
    private BankAccountRepository bankAccountRepository;

    @Transactional
    public Optional<BankAccount> findByIdWithPessimisticLock(Long id) {
        return bankAccountRepository.findByIdWithPessimisticLock(id);
    }
}

6. 컨트롤러 클래스

컨트롤러에서 서비스를 호출합니다.

java

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;

import java.util.Optional;

@RestController
public class BankAccountController {

    @Autowired
    private BankAccountService bankAccountService;

    @GetMapping("/bank-accounts/{id}/lock")
    public Optional<BankAccount> findByIdWithPessimisticLock(@PathVariable Long id) {
        return bankAccountService.findByIdWithPessimisticLock(id);
    }
}

이제 /bank-accounts/{id}/lock 경로로 GET 요청을 보내면 해당 ID를 가진 은행 계좌에 비관적 락을 걸고 데이터를 가져올 수 있습니다.

이렇게 하면 QueryDSL을 사용하여 비관적 락을 적용할 수 있습니다. setLockMode(LockModeType.PESSIMISTIC_WRITE) 메서드를 사용하여 필요한 락 모드를 설정할 수 있습니다.