일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
- kubernetes
- Adapter 패턴
- MySQL
- devops
- MSA
- java
- ansible
- Semaphore
- 마이크로서비스
- 클라우드 네이티브
- Microservice
- spring microservice
- 자바
- ingress
- 클라우드 네이티브 자바
- decorator 패턴
- 동기화
- Stress test
- Kotlin
- Algorithm
- cloud native
- CRD
- 쿠버네티스
- 머신러닝
- nGrinder
- 익명클래스
- 헬름
- Spring
- 코틀린
- cloud native java
- Today
- Total
카샤의 만개시기
JPA에서 Optimistic Lock과 Pessimistic Lock 본문
낙관적 락 (Optimistic Lock)
트랜잭션 대부분 충돌이 발생하지 않는다고 가정하는 방법으로써 어플리케이션이 제공하는 락 방식입니다. 그러므로 읽는 시점에 Lock을 사용하지 않기 때문에 데이터를 수정하는 시점에 다른 사용자에 의해 데이터가 변경되었는지 변경여부를 확인해야 합니다.
이렇게 낙관적 락은 트랜잭션을 커밋하기 전까지는 트랜잭션의 충돌 여부를 알 수 없습니다.
@Version
JPA가 제공하는 낙관적 락을 사용하려면 @Version 어노테이션을 사용하여 버전 관리를 추가하면 되며 지원되는 타입은 long, Long, int, Integer, short, Short, TimeStamp 이다.
@Version 어노테이션을 붙이면 엔티티가 수정될때 자동으로 버전이 하나씩 증가하며, 수정할때 조회 시점의 버전과 다를 경우 OptimisticLockException
예외가 발생한다.
Lock Modes
JPA는 두가지의 낙관적 락 모드를 지원합니다.
- OPTIMISTIC (Read)
@Version을 포함하는 모든 엔티티에 대한 낙관적 락을 얻는다.
이를 통해 dirty read와 non-repeatable read를 방지한다. - OPTIMISTIC_FORCE_INCREMENT (Write)
낙관적 락을 사용하면서 버전 정보를 강제로 증가시킨다.
사용법
Find
entityManager.find(Student.class, studentId, LockModeType.OPTIMISTIC);
Query
Query query = entityManager.createQuery("from Student where id = :id");
query.setParameter("id", studentId);
query.setLockMode(LockModeType.OPTIMISTIC_INCREMENT);
query.getResultList()
Explicit Locking
Student student = entityManager.find(Student.class, id);
entityManager.lock(student, LockModeType.OPTIMISTIC);
Refresh
Student student = entityManager.find(Student.class, id);
entityManager.refresh(student, LockModeType.READ);
NamedQuery
@NamedQuery(name="optimisticLock",
query="SELECT s FROM Student s WHERE s.id LIKE :id",
lockMode = WRITE)
비관적 락 (Pessimistic Lock)
자원에 대한 동시 요청이 발생하여 일관성에 문제가 생길 것이라고 비관적으로 생각하고 이를 방지하기 위해 우선 락을 거는 방식이다.
Pessimistic Lock은 배타적 락(Exclusive Lock)과 공유 락(Shared Lock) 두가지 타입이 있다.
Shared Lock은 다른 사용자가 동시에 데이터를 읽을 수는 있지만 Write는 할 수 없다.
Exclusive Lock은 데이터를 변경하고자 할 때 사용되며, 트랜잭션이 완료될 때까지 유지되어 해당 Lock이 해제될 때까지 다른 트랜잭션은 해당 데이터에 읽기를 포함하여 접근을 할 수 없다.
대표적으로 SELECT FOR UPDATE를 예로 들수 있다.
Lock Modes
JPA는 세가지의 비관적 락 모드를 지원합니다.
- PESSIMISTIC_READ
Shared Lock을 얻고 데이터가 업데이트되거나 삭제되지 않도록합니다. - PESSIMISTIC_WRITE
Exclusive Lock을 획득하고 데이터를 읽거나, 업데이트하거나, 삭제하는 것을 방지합니다. - PESSIMISTIC_FORCE_INCREMENT
PESSIMISTIC_WRITE와 유사하게 작동하며 엔티티의 버전 속성을 추가로 증가시킵니다.
Exception
- PersistenceException
한번에 하나의 Lock만 얻을 수 있으며, 락을 가져오는데 실패하면 발생하는 예외 - LockTimeoutException
락을 기다리다 설정해놓은 wait time을 지났을 경우 발생하는 예외 - PersistanceException
영속성 문제가 발생했을때의 예외
사용법
Find
entityManager.find(Student.class, studentId, LockModeType.PESSIMISTIC_READ);
Query
Query query = entityManager.createQuery("from Student where studentId = :studentId");
query.setParameter("studentId", studentId);
query.setLockMode(LockModeType.PESSIMISTIC_WRITE);
query.getResultList()
Explicit Locking
Student resultStudent = entityManager.find(Student.class, studentId);
entityManager.lock(resultStudent, LockModeType.PESSIMISTIC_WRITE);
Refresh
Student resultStudent = entityManager.find(Student.class, studentId);
entityManager.refresh(resultStudent, LockModeType.PESSIMISTIC_FORCE_INCREMENT);
NamedQuery
@NamedQuery(name="lockStudent",
query="SELECT s FROM Student s WHERE s.id LIKE :studentId",
lockMode = PESSIMISTIC_READ)
Lock Scope
- PessimisticLockScope.NORMAL
기본값으로써 해당 entity만 lock이 걸립니다.
@Inheritance(strategy = InheritanceType.JOINED)와 같이 조인 상속을 사용하면 부모도 함께 잠급니다. - PessimisticLockScope.EXTENDED
@ElementCollection, @OneToOne , @OneToMany 등 연관된 entity들도 lock이 됩니다.
'Java > Spring' 카테고리의 다른 글
RestTemplate (2) | 2019.07.07 |
---|---|
Spring AOP, Proxy (0) | 2019.07.04 |