반응형
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) 메서드를 사용하여 필요한 락 모드를 설정할 수 있습니다.