-
Transaction 격리 레벨 / 전파 모델JAVA 2023. 8. 6. 17:30
격리 수준에따라 발생할 수 있는 문제점
Dirty Read
특정 트랜잭션이 데이터를 변경하고 아직 COMMIT 하지 않은 상태에서 다른 트랜잭셔인 변경 내용을 조회할 수 있는 문제
Non-Repeatable Read
같은 트랜잭션 내에서 같은 데이터를 반복적으로 조회했을 때 읽어온 데이터가 다른 문제
Phantom Read
Non-Repeatable Read의 한 종류로 조회해온 결과의 행이 새로 생기거나 없어지는 문제
Transaction Isolation Level
트랜잭션 격리수준은 동시에 여러 트랜잭션이 진행될 때 현재 트랜잭션의 작업을 다른 트랜잭션에게 어떻게 적용 시킬지를 결정한다. 트랜잭션 격리 수준은 아래와같이 크게 4개로 나뉜다. 아래로 갈 수록 트랜잭션간 고립 정도가 높아지며, 성능이 떨어진다.
READ UNCOMMITTED
가장 격리 수준이 낮은 단계로, 어떤 트랜잭션의 변경 내용이 COMMIT과 ROLLBACK 상관없이 다른 트랜잭션에 적용되어 보여진다.
- 트랜잭션 A 에서 데이터 수정, 아직 COMMIT 하지 않음
- 트랜잭션 B에서 해당 데이터 조회, 수정된 데이터를 결과로 받음
- 트랜잭션 A롤백
- 트랜잭션 B는 여전히 잘못 수정된 값을 사용
이처럼 READ UNCOMMITTED에서는 Dirty Read, Phantom Read 등 여러 문제가 발생할 수 있다. 이때문에 READ UNCOMMITED는 RDMS 표준에서 인정하지도 않는 단계이다.
READ COMMITED
이 단계에서는 어떤 트랜잭션이 변경 내용을 COMMIT 해야 다른 트랜잭션에 영향을 주는 단계이다. ORACLE DBMS의 기본 설정으로 되어있다.
RDBMS 는 변경 전의 레코드를 UNDO 라는 공간에 백업해둔다. 이렇게되면 변경 전/후 데이터가 모두 존재하게되는데 이렇게 하나의 레코드에대해 여러 버전의 데이터가 있다해서 이를 MVCC(Multi-Version Concurrency Control, 다중 버전 동시성 제어) 라고 한다.
READ COMMITED에서는 이 UNDO 공간의 변경전 데이터를 이용하여 트랜잭션이 커밋 되기 전에는 다른 트랜잭션에 영향을주지 않도록 한다. 하지만 이 단계에서도 다음과 같은 상황에서 문제가 발생할 수 있다.
- 트랜잭션 B에서 데이터 조회, 100을 결과로 받음
- 트랜잭션 A에서 데이터를 200이라 수정 후 COMMIT
- 트랜잭선 B에서 데이터 다시 조회, 200이라는 결과 반환
이처럼 하나의 트랜잭션에서 같은 SELECT를 실행할경우 항상 같은 결과를 반환해야 한다는 REPEATABLE READ 정합성에 어긋난다.
REPEATABLE READ
각각의 트랜잭션에는 순차적으로 증가하는 트랜잭션 번호가 있다. 배업 레코드에 저장할때 이 트랜잭션 번호를 같이 저장하여 자신보다 나중에 실행된 트랜잭션의 경우 무시하여 REPEATABLE READ 정합성을 해결한다.
- TID 1 트랜잭션에서 데이터 조회 결과로 100 반환받음.
- TID 2 트랜잭션에서 데이터 200으로 수정 후 COMMIT
- TID 1 트랜잭션에서 다시 데이터 조회.
- TID 2 트랜잭션이 데이터를 200으로 수정한 기록이 있으니 UNDO 로그를 조회
- 백업되어있는 이전 데이터 100을 그대로 다시 조회
하지만 이런 REPEATABLE READ 단계도 Phantom Read 문제를 발생시킬 수 있는데, 새로운 row가 insert 되는것을 막지는 않기 때문이다.
- TID 2 트랜잭션에서 데이터 조회. 데이터 1개 반환
- TID 1 트랜잭션에서 데이터 INSERT
- TID 2 트랜잭션에서 데이터 다시 조회. 데이터 2개 반환
SERIALIZABLE
SERIALIZABLE은 가장 엄격한 격리 수준이다. 여러 트랜잭션이 동일한 레코드에 동시 접근할 수 없다.
순수 조회용 SELECT 작업시에도 대상 레코드에 락을 건다. 모든 트랜잭션이 순차적으로 처리되어야하기때문에 성능이 매우 떨어진다.
단계별 문제 정리
다른 블로그에 단계별로 발생할 수 있는 문제를 잘 정리한 표가있어서 첨부한다.
Transaction Propagation
트랜잭션 전파 속성이란, 이미 진행중인 트랜잭션이 있을때 새로운 트랜잭션을 어떻게 할지 결정하는 것이다.
Spring 에서 제공하는 트랜잭션 어노테이션을 사용하여 여러 트랜잭션을 묶어 하나의 커다란 트랜잭션 경계를 만들 수 있다.
Spring에서는 총 7가지 전파 속성을 제공하며 다음과 같다.
REQUIRED
- 기본값으로 트랜잭션이 필요로 하다는 의미이다.
- 부모의 트랜잭션이 존재한다면 부모 트랜잭션으로 합류한다.
- 기존 트랜잭션이 없다면 새로운 트랜잭션을 만든다.
- 중간에 롤백이 발생하면 모두 롤백된다.
SUPPORTS
- 트랜잭션이 있으면 사용하고 없어도 된다는 의미이다.
- 기존 트랜잭션이 존재하면 합류한다.
- 기존 트랜잭션이 없으면 트랜잭션 없이 진행한다
MANDATORY
- 트랜잭션이 반드시 필요하다
- 기존 트랜잭션이 없다면 예외를 발생시킨다
- 기존 트랜잭션이 있다면 합류한다.
REQUIRES_NEW
- 항상 새로운 트랜잭션이 필요하다는 의미이다.
- 기존 트랜잭션이 없다면 트랜잭션을 새로 생성한다
- 기존 트랜잭션이 있어도 새로운 트랜잭션을 생성한다
NOT_SUPPORTED
- 트랜잭션을 사용하지 않는다는 의미이다
- 기존 트랜잭션이 없으면 트랜잭션 없이 진행한다
- 기존 트랜잭션이 있으면 기존 트랜잭션 보류 후 트랜잭션 없이 진행한다
NEVER
- 기존의 트랜잭션도 허용하지 않는다는 의미이다.
- 기존 트랜잭션이 없다면 트랜잭션 없이 진행한다
- 기존 트랜잭션이 있다면 예외를 발생시킨다
NESTED
- 중첩 트랜잭션을 생성한다
- 기존 트랜잭션이 없다면 새로운 트랜잭션을 생성한다.
- 기존 트랜잭션이 있다면 중첩 트랜잭션을 생성한다.
- DB 드라이버가 지원하는지 확인이 필요하며 JPA 에서는 사용이 불가능하다.
출처
https://mangkyu.tistory.com/299
https://hudi.blog/transaction-isolation-level/
https://deveric.tistory.com/86
https://mangkyu.tistory.com/269
'JAVA' 카테고리의 다른 글
Java Generic Compile 동작 (0) 2023.09.11 JVM Memory Area (0) 2023.09.08 Java 버전 별 ArrayList add 동작 (0) 2023.09.06 Java Thread Safety 한 개발 (0) 2023.08.29 Singleton 구현 기법 (0) 2023.08.27