카테고리 없음

"트랜잭션은 만능이 아니다"

박수연_01 2023. 11. 14. 19:53

트랜잭션 

데이터베이스의 상태를 변화시키는 수행 작업의 단위

 

 

동시성 문제에 대해 트랜잭션을 사용하면 해결된다고 생각할 수 있지만 사실 그렇지 않다.

트랜잭션은 길수록 오버헤드가 발생하기 때문이다.

 

jpa respository에서 제공하는 연산은 트랜잭션이 적용된다.

 

트랜잭션을 계속 걸면 성능과 트레이드 오프가 생기게 된다.

 

우리는 어느정도의 수준으로 트랜잭션을 걸지 정해야한다.

 

트랜잭션을 어느 범위 까지 걸 것인지 결정하는 것은 전파전략이라고한다.

Spring은 @Transactional (선언적 트랜잭션)을 이용해 여러 트랜잭션을 묶어 하나의 큰 트랜잭션 경계를 만들 수 있다.

 

격리수준

- Read Uncommitted

- Read Committed 

- Repeatable Read 

- Serializable

 

Read Uncommitted

가장 하위 레벨의 격리 수준으로 트랜잭션이 commit 되지 않은 데이터를 다른 트랜잭션이 읽을 수 있도록 허용한다.

 

 Read Committed

트랜잭션의 커밋이 확정된 데이터만 읽을 수 있게 허용한다.

 

Repeatable Read

트랜잭션이 시작되기 전에 커밋된 내용에 대해서만 읽을 수 있도록 허용된다. 트랜잭션 도중 다른 트랜잭션이 커밋 되어도, 새로 커밋된 데이터는 보이지 않게 된다.

 

Serializable

가장 높은 수준의 격리 수준으로 특정 트랜잭션이 수행중엔 해당 테이블에 다른 트랜잭션이 UPDATE, DELETE, INSERT를 못하게 막는다. 동시성이 가장 낮은 격리 수준이기 때문에 거의 사용하지 않는다고 한다.

 

 

 

"아래로 내려갈수록 트랜잭션간 고립 정도가 높아지며, 성능이 떨어지는 것이 일반적이다.
일반적인 온라인 서비스에서는 READ COMMITTED나 REPEATABLE READ 중 하나를 사용한다.

따로 설정하지 않는다면 디폴트로 설정되는 듯 하다 : (oracle = READ COMMITTED, mysql = REPEATABLE READ)"

 

사용예시

  @Transactional(isolation=Isolation.SERIALIZABLE, propagation=Propagation.REQUIRES_NEW)

 

트랜잭션은 논리적으로 5가지의 상태에 있을 수 있다.

  • Active
    • 트랜잭션이 현재 실행 중인 상태
  • Failed
    • 트랜잭이 실행되다 오류가 발생해서 중단된 상태
  • Aborted
    • 브랜잭션이 비정상 종료되어 Rollback 이 수행된 상태
  • Partially Committed
    • 트랜잭션의 연산이 마지막까지 실행되고 Commit이 되기 직전 상태
  • Committed
    • 트랜잭션이 성공적으로 종료되어 Commit 연산을 실행한 후의 상태

 

몇가지 전파레벨에 대해 알아보자 (여기 설명한 것보다 더 많은 전파레벨이 존재한다)

 

@Transactional(propagation = Propagation.REQUIRED)
public void doSomething() { ... }

 

특정 메소드의 트랜잭션이 Propagation.REQUIRED로 설정되었을 때의 트랜잭션 동작은 다음과 같다. 기본적으로 해당 메소드를 호출한 곳에서 별도의 트랜잭션이 설정되어 있지 않았다면 트랜잭션를 새로 시작한다. 만약, 호출한 곳에서 이미 트랜잭션이 설정되어 있다면 기존의 트랜잭션 내에서 로직을 실행한다. (동일한 연결 안에서 실행된다.) 예외가 발생하면 롤백이 되고 호출한 곳에도 롤백이 전파된다. 이러한 Propagation.REQUIRED 동작 방식을 원할 경우 기본값으로 설정되어 있기 때문에 생략해도 된다.

@Transactional(propagation = Propagation.REQUIRES_NEW)
public void doSomething() { ... }

 

Propagation.REQUIRES_NEW로 설정되었을 때에는 매번 새로운 트랜잭션을 시작한다. (새로운 연결을 생성하고 실행한다.) 만약, 호출한 곳에서 이미 트랜잭션이 설정되어 있다면(기존의 연결이 존재한다면) 기존의 트랜잭션은 메써드가 종료할 때까지 잠시 대기 상태로 두고 자신의 트랜잭션을 실행한다. 새로운 트랜잭션 안에서 예외가 발생해도 호출한 곳에는 롤백이 전파되지 않는다. 2개의 트랜잭션은 완전히 독립적인 별개로 단위로 작동한다.

 

@Transactional(propagation = Propagation.NESTED)
public void doSomething() { ... }

Propagation.NESTED는 기본적으로 앞서 설명한 Propagation.REQUIRED와 동일하게 작동한다. 중요한 차이점은, SAVEPOINT를 지정한 시점까지 부분 롤백이 가능하다는 것이다. 유의할 점은, 데이터베이스가 SAVEPOINT 기능을 지원해야 사용이 가능하다.

 

아직까지 프로젝트에서 트랜잭션에 대해 깊게 생각하고 적용해 본 적은 없는데 조금더 공부 한 후 적용해 보도록 해야겠다. 

 

트랜잭션 정합성내용 추가 필요(lock)

 

출처

https://woonys.tistory.com/entry/Transactional%EC%9D%80-%EB%A7%8C%EB%8A%A5%EC%9D%B4-%EC%95%84%EB%8B%99%EB%8B%88%EB%8B%A4-2-%ED%8A%B8%EB%9E%9C%EC%9E%AD%EC%85%98%EC%9D%98-%EA%B2%A9%EB%A6%AC%EC%84%B1%EA%B3%BC-lock

 

@Transactional은 만능이 아닙니다 -2 트랜잭션의 격리성과 lock

Introduction 지난 시간에는 트랜잭션의 개념과 어떨 때 트랜잭션을 사용해야 하는지에 대해서 배웠다. 그런데 1부에서 얘기했던 것과 같이, @Transactional을 제거했더니 Exception이 발생했다. 이 문제는

woonys.tistory.com

https://okky.kr/articles/1151991

 

OKKY - Spring Boot, @Transactional 전파 레벨 정리

안녕하세요.제 블로그에 작성했던 글을 가져왔습니다. 출처만 남겨주시면 자유롭게 퍼가셔도 됩니다.https://jsonobject.tistory.com/467  (지단로보트의 블로그) @Transactional 사용시 주의사항 @Transactional

okky.kr

https://developyo.tistory.com/250

 

@Transactional Propagation (전파속성), Isolation (격리수준레벨) 그리고 synchronized

1. Transaction 설정방법 트랜잭션 설정 방법은 이곳을 참고. 2. Isolation SQL 의 Isolation level 과 동일하게 동작 (SQL 격리수준 속성에 대한 자세한 내용은 이곳을 참고) - READ_UNCOMMITED : commit 되지 않은 데

developyo.tistory.com