JPA 트랜잭션 격리수준
일관성이 없는 데이터를 허용하는 수준
트랜잭션이 보장해야 하는 ACID중 격리성과 관련된 내용인데 격리성을 완벽히 보장하려면 동시성 처리 성능이 매우 나빠진다. 이런 문제로 인해 ANSI 표준은 트랜잭션의 격리 수준을 4단계로 나누어 정의했다.
A : Atomicity / C : Consistency / I : Isolation / D : Durability
트랜잭션 관리 포인트 3
1. Dirty Read : 변경된 데이터가 아직 미완성인데 다른 트랜잭션에서 읽어가는 것
2. Nonrepeatble Read : 트랜잭션이 수행중인데 다른 트랜잭션이 읽고 있는 데이터를 수정해서 쿼리 결과가 달라지는 것
3. Phantom Read : 동일한 쿼리가 다른 값을 반환하는 것
아래로 내려 갈수록 동시성이 높아지는 대신 속도가 느려진다. ( lv.0 -> lv.3)
위로 올라 갈수록 동시성이 떨어지는 대신 속도가 빨라진다. (lv.3 -> lv.0)
격리수준
- READ UNCOMMITED (lv.0)
- 커밋되지 않은 데이터도 읽을 수 있음
- A트랜잭션에서 데이터를 변경하려다 에러가 발생해서 Rollback을 했다고 치면 A트랜잭션이 실행되는 동안 데이터를 요청한 B 트랜잭션은 잘못된 데이터를 읽고 있을 수가 있다. Dirty Read, Dirty Write이 가능함
- Dirty Read는 방지 X, Noorepeatable read방지 X, Phantom Read 방지 X
- 커밋되지 않은 데이터도 읽을 수 있음
- READ COMMITED (lv.1)
- 커밋된 데이터만 불러온다. (= 반복해서 같은 데이터를 불러올 수 없다)
- SELECT 문장이 수행되는 동안 해당 데이터에 Shared Lock(읽기 가능, 변경 불가)이 걸리는 레벨
- 어떠한 사용자가 A라는 데이터를 B라는 데이터로 변경하는 동안 다른 사용자는 해당 데이터(B)에 접근할 수 없습니다.
- Dirty Read 방지 O , Noorepeatable read 방지 X
- SELECT 문장이 수행되는 동안 해당 데이터에 Shared Lock(읽기 가능, 변경 불가)이 걸리는 레벨
- 커밋된 데이터만 불러온다. (= 반복해서 같은 데이터를 불러올 수 없다)
- REPEATABLE READ (lv.2)
- 트랜잭션 동안에는 한번 조회한 데이터를 계속 조회해도 같은 데이터가 나오지만, 만약 다른 트랜잭션에서 데이터를 추가한 경우 기존 트랜잭션에서 반복 조회하면 결과 집합이 새로 추가된 데이터를 포함한 결과를 가져오게 된다.
- Dirty Read 방지 O, Noorepeatable read 방지 O, Phantom Read 방지 X
- 트랜잭션 동안에는 한번 조회한 데이터를 계속 조회해도 같은 데이터가 나오지만, 만약 다른 트랜잭션에서 데이터를 추가한 경우 기존 트랜잭션에서 반복 조회하면 결과 집합이 새로 추가된 데이터를 포함한 결과를 가져오게 된다.
- SERIALIZABLE (lv.3)
- 모든 트랜잭션을 순서대로 실행한다.
- Dirty Read 방지 O, Noorepeatable read 방지 O, Phantom Read 방지 O
JPA를 사용하면 격리 수준을 READ_COMMITED로 가정하는데 만약 일부 로직에 더 높은 격리 수준이 필요하면 비관적 락과 낙관적 락 중에 선택을 하여 사용해야 한다.
비관적 락
트랜잭션 간 충돌이 발생한다고 가정하여 우선 락을 건다, 데이터베이스가 제공하는 락 기능을 사용한다.
데이터를 수정하는 즉시 트랜잭션 충돌을 감지하며 예외를 발생시킨다.
비관적 락을 사용하면 락을 획득할 때까지 트랜잭션이 대기한다. 무한정 기다릴 수 없으므로 타임아웃 시간을 줄 수 있다.
낙관적 락
트랜잭션 대부분은 충돌이 발생하지 않는 다고 가정하며, JPA가 제공하는 버전 관리 기능을 사용한다. (어플리케이션 단 레벨)
트랜잭션을 커밋하기 전까지는 트랜잭션의 충돌을 알 수 없다는 특징이 있다.
JPA에서 제공하는 @Version 어노테이션을 사용하며, 최초 커밋만 인정되어 두번째 커밋에선 예외를 발생시킨다.
JPA의 추천하는 전략은 READ_COMMITTED + 낙관적 락
참고.
'JPA & DB' 카테고리의 다른 글
[JPA] mappedby 그리고 join column - 양방향 (0) | 2023.03.02 |
---|---|
Hikari Option 정리 (0) | 2022.03.25 |
JPA Persistence Context 그리고.. Flush / Lazy Loading / N+1 Problem (0) | 2021.11.15 |
Cascade 이해 및 orphanRemoval=true vs CascadeType.REMOVE (0) | 2020.05.15 |
[JPA] 복합키에서 equals () 및 hashCode () 구현하는 이유 (0) | 2020.03.06 |