Backend/Spring

Spring Transactional Isolation

keepbang 2023. 1. 4. 11:20

이전 글 : Propagation

 

Spring Transactional Propagation

이번에 회사에서 transactional anotation을 사용하면서 부족한 게 많아 정리를 한다! @Transactional DB는 트랜잭션 단위로 쿼리를 실행하며 commit을 통해 작업내용을 처리하고 트랜잭션을 종료한다. spring

keepbang.tistory.com


Propagation에 이어서 Transactional의 속성인 isolation을 정리해볼까 한다.

 

Transaciton은 ACID라는 원칙을 보장해야 한다고 한다.

Atomicity(원자성) : 트랜잭션내의 모든 작업은 완료되거나 모두 실패해야 한다. 트랜잭션의 작업중 하나만 완료하거나 할 수 없고 하나라도 실패하면 모두 실패한 후 롤백 처리 되어야한다.

Consistency(일관성) : 트랜잭션이 끝날때 데이터들은 일관된 상태를 유지해야 한다.

Isolation(격리성) : 여러 트랜잭션들이 서로 관여하지 않는걸 보장한다.

Durability(지속성) : 트랜잭션이 성공했을 때 해당 결과가 영구적으로 반영 되어야 한다.

 

위와같은 원칙들을 모두 지키고자 하면 동시성이 떨어지고 성능이 안 좋아져서 모두 지키기는 어렵다.

 

때문에 위의 원칙중 isolation level을 설정해서 동시성을 높이는 방법이 존재한다. isolation level을 낮추면 데이터의 일관성은 떨어지겠지만 동시성은 높아진다.

isolation level은 총 4가지로 READ UNCOMMITTED, READ COMMITTED, REPEATABLE READ, SERIALIZABLE 이 있다.

level에 따라서 table에 lock을 걸고 level이 높아질수록 더 강한 lock을 걸 수 있다. lock이 풀리는 시점은 transaction이 종료되는 시점에 풀리게 된다.

 

우리가 주로 사용하는 DB들도 isolation을 기본적으로 제공한다. mysql은 위에서 말한 격리레벨을 전부 지원하고 Repeatable read를 기본값을 가지고있다. 오라클은 Read committed(default)와 Serializable을 지원하고 있다.

 


READ UNCOMMITTED

쿼리를 실행할 때 아직 commit되지 않은 데이터를 읽을 수 있다.

그래서 존재하지 않는 데이터를 읽을 수 있는데 아래와 같은 상황이 발생한다.

1. Transaction A -> insert into table(id) values(1) [아직 커밋되지 않음]
2. Transaction B -> select id from table -> 1 조회
3. Transaction A 에서 에러가 발생해 rollback됨

 

사용자는 분명 조회해서 데이터를 얻었는데 이후에 다시 조회 했을 때 데이터가 없는 경우가 발생된다. 이런 현상을 dirty read라고 한다.

 

READ COMMITTED

Read Committed를 사용하면 커밋된 데이터만 읽을 수 있기 때문에 dirty read가 발생되지 않는다.

하지만 한 트랜잭션에서 동시성 문제로 같은 쿼리가 다른 결과를 보여 줄 수 있다.

1. Transaction A -> select name from table where id = 1 ->  name : kim
2. Transaction B -> update table set name = kim2 where id = 1 -> commit
3. Transaction A -> select name from table where id = 1 -> name : kim2

 

위와 같은 현상을 Non repeatable read 라고 한다. 위 현상 외에도  Phantom read가 발생 할 수도 있다.

Phantom read는 다른 트랜잭션의 입력/삭제 작업으로 동일한 쿼리가 다른 결과를 보여주는 것을 말한다.

1. Transaction A -> select id from table ->  [1]
2. Transaction B -> insert into table(id) values(2) -> commit
3. Transaction A -> select id from table ->  [1,2]

 

REPEATABLE READ

트랜잭션이 완료될때 까지 select 문이 사용하는 모든 데이터에 lock을 걸어서 다른 사용자는 해당 데이터에 대한 수정이나 삭제가 불가능하다.

첫 read시의 스냅샷을 보관하여 다른 트랜잭션이 커밋되어도 일관성이 보장된다.

 

동시성 부작용 중 dirty read, non repeatable read를 방지한다.

 

SERIALIZABLE

가장 높은 수준의 격리 수준으로 위에서 말한 부작용들을 모두 방지한다. 하지만 그만큼 동시 호출 시 순차적으로 수행되기 때문에 동시성이 낮아지게되고 액세스 속도가 낮아질 수 있다.

 

안전하게 데이터를 저장할 수 있지만 deadlock이 발생 될 수 있게 때문에 deadlock이 발생 되는 상황이 아닌지 확인한 다음 사용해야 한다.

 

 

[참고]

https://ojava.tistory.com/207

https://suhwan.dev/2019/06/09/transaction-isolation-level-and-lock/

https://mysqldba.tistory.com/334