우당탕탕

[JPA] 낙관적 락(Optimistic Lock)과 비관적 락(Pessimistic Lock)에 대해 본문

언어/Java

[JPA] 낙관적 락(Optimistic Lock)과 비관적 락(Pessimistic Lock)에 대해

모찌모찝 2023. 6. 16. 12:07
낙관적 락, 비관적 락에 대해


JPA를 사용하여 데이터베이스와 연결된 애플리케이션을 개발할 때, 동시성 처리와 관련된 이슈가 발생할 수 있다.
이러한 이슈를 해결하기 위한 방법 중 하나는 락(lock)을 사용하는 것이다.
이번 포스팅에는 낙관적 락과 비관적 락에 대해 알아보고, 예제코드와 이를 사용하는 이유 및 장단점을 함께 써보겠다.

낙관적 락(Optimistic Lock)

낙관적 락은 충돌이 거의 발생하지 않을 것이라고 가정하고, 충돌이 발생한 경우에 대비하는 방식이다.
낙관적 락은 JPA에서 버전(Version) 속성을 이용하여 구현할 수 있다. 낙관적 락의 특징으로는 충돌 발생확률이 낮고, 지속적인 락으로 인한 성능저하를 막을 수 있다.

아래는 예시 코드이다.
1. Entity

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

    @Version
    private Long version;

    private String data;
}

2. Repository

@Repository
public interface SampleEntityRepository extends JpaRepository<SampleEntity, Long> {
}

3. Service

@Service
public class SampleEntityService {
    @Autowired
    private SampleEntityRepository sampleEntityRepository;

    public SampleEntity updateData(Long id, String newData) {
        SampleEntity sampleEntity = sampleEntityRepository.findById(id).orElseThrow();
        sampleEntity.setData(newData);
        return sampleEntityRepository.save(sampleEntity);
    }
}

작동원리로는 SampleEntity 클래스에 @Version 어노테이션을 이용하여 version 필드로 지정한다.
데이터를 수정할 때 같은 id 값이지만 다른 사용자에 의한 변경이 발생하면 version 값이 다르게 되고, 이때 예외가 발생하므로 충돌로부터 안전하게 처리할 수 있다.

비관적 락(Pessimistic Lock)

비관적 락은 충돌이 발생할 확률이 높다고 가정하여, 실제로 데이터에 액세스 하기 전에 먼저 락을 걸어 충돌을 예방하는 방식이다. 비관적 락은 JPA에서 제공하는 LockModeType을 사용하여 구현할 수 있다.

아래는 예시코드이다
1. Repository

@Repository
public interface SampleEntityRepository extends JpaRepository<SampleEntity, Long> {
}

2. Service

@Service
public class SampleEntityService {
    @Autowired
    private SampleEntityRepository sampleEntityRepository;

    @Autowired
    private EntityManager entityManager;

    @Transactional
    public SampleEntity updateDataWithPessimisticLock(Long id, String newData) {
        SampleEntity sampleEntity = entityManager.find(SampleEntity.class, id, LockModeType.PESSIMISTIC_WRITE);
        sampleEntity.setData(newData);
        entityManager.flush();
        return sampleEntity;
    }
}

 

위 코드를 설명해보면 EntityManagerfind 메소드에 락 타입(LockModeType.PESSIMISTIC_WRITE)을 지정하여 데이터에 락을 걸어두고, 변경 작업이 끝난 후에 락을 해제한다. 이를 통해 다른 트랜잭션이 동시에 수정할 수 없어 동시성 처리 이슈를 방지할 수 있게 된다.

이제 낙관적 락과 비관적 락에 대해 알아보았으니 이들의 장단점에 대해서도 알아보자

낙관적 락

장점: 리소스 경쟁이 적고 락으로 인한 성능저하가 적다.
단점: 충돌 발생 시 처리해야 할 외부 요인이 존재한다.

비관적 락

장점: 충돌 발생을 미연에 방지하고 데이터의 일관성을 유지할 수 있다.
단점: 동시 처리 성능 저하 및 교착상태(Deadlock) 발생 가능성이 있다.


위에서 알아본 내용처럼 낙관적 락과 비관적 락은 각각의 사용 상황에 따라 선택할 수 있다. 충돌 발생 확률이 낮고 성능 저하를 예방하려면 낙관적 락을 사용하면 되고, 충돌을 미연에 방지하고 데이터의 일관성을 유지하려면 비관적 락을 사용하면 된다. 선택한 락 방식에 따라 JPA를 효과적으로 사용하여 동시성 처리 이슈를 해결할 수 있다.

 

Comments