본문 바로가기
JAVA & KOTLIN

[SPRING] Spring @Transactional

by nozee 2024. 12. 22.
반응형

Transaction

데이터베이스 관리 시스템 또는 유사한 시스템에서 상호작용의 단위이다.

여기서 유사한 시스템이란 트랜잭션이 성공과 실패가 분명하고 상호 독립적이며, 일관되고 믿을 수 있는 시스템을 의미

데이터의 정합성을 보장하기 위해 고안된 방법

 

Transaction 특징

  • 원자성(Atomicity)
    • 한 트랜잭션 내에서 실행한 작업들은 하나로 간주한다. 즉, 모두 성공 또는 모두 실패
  • 일관성(Consistency)
    • 트랜잭션은 일관성 있는 데이터베이스 상태를 유지한다. (data integrity 만족 등.)
  • 격리성(Isolation)
    • 동시에 실행되는 트랜잭션들이 서로 영향을 미치지 않도록 격리해야 한다.
  • 지속성(Durability)
    • 트랜잭션을 성공적으로 마치면 결과가 항상 저장되어야 한다.

 

Spring에서 트랜잭션 처리 방법

스프링에서는 트랜잭션 처리를 지원하는데 그 중 어노테이션 방식으로 @Transactional을 선언하여 사용하는 방법이 일반적이며, 선언적 트랜잭션이라 부른다.

클래스, 메서드위에 @Transactional이 추가되면, 이 클래스에 트랜잭션 기능이 적용된 프록시 객체가 생성된다.

이 프록시 객체는 @Transactional이 포함된 메소드가 호출 될 경우, PlatformTranactionManager를 사용하여 트랜잭션을 시작하고, 정상 여부에 따라 Commit 또는 Rollback 한다.

 

 

다 수 트랜잭션이 경쟁시 발생할 수 있는 문제

Dirty Read

트랜잭션 A가 어떤 값 1에서 2로 변경하고 아직 커밋하지 않은 상황에서 트랜잭션 B가 같은 값을 읽는 경우 트랜잭션 B는 2가 조회 된다.

트랜잭션 B가 2를 조회 한 후 혹시 A가 롤백되면 결국 트랜잭션 B는 잘못된 값을 읽게 된 것이다. 즉, 아직 트랜잭션이 완료되지 않은 상황에서 데이터에 접근을 허용할 경우 발생할 수 있는 데이터 불일치이다.

 

 

Non-Repeatable Read

트랜잭션 A가 어떤 값 1을 읽었따. 이후 A는 같은 쿼리를 또 실행할 예정인데, 그 사이에 트랜잭션 B가 값 1을 2로 바꾸고 커밋해 버리면 A가 같은 쿼리를 두번 날리는 사이 두 쿼리의 결과가 다르게 되어 버린다.

즉, 한 트랜잭션에서 같은 쿼리를 두 번 실행했을 때 발생할 수 있는 데이터 불일치이다.

(Dirty Read에 배해서는 발생할 확률이 적다)

 

 

Phantom Read

트랜잭션 A가 어떤 조건을 사용하여 특정 범위의 값들 [0,1,2,3,4] 읽었다.

이후 A는 같은 쿼리를 실행할 예정인데, 그 사이에 트랜잭션 B가 같은 테이블에 값 [5,6,7]을 추가해 버리면 A가 같은 쿼리 두 번을 날리는 사이 두 쿼리의 결과가 다르게 되어 버린다.

즉, 한 트랜잭션에서 일정 범위의 레코드를 두 번 이상 읽을 때 발생하는 데이터 불일치이다.

 

Spring Transactional

Isolation(격리 수준)

트랜잭션에서 일관성이 없는 데이터를 허용하도록 하는 수준

 

  • Default
    • 기본 격리 수준(기본설정, DB의 Isolation Level을 따름)
  • READ_UNCOMMITED(level 0)
    • 커밋되지 않는 (트랜잭션 처리중인) 데이터에 대한 읽기를 허용
    • 즉 어떤 사용자가 A라는 데이터를 B라는 데이터로 변경하는 동안 다른 사용자는 B라는 아직 완료되지 않은 (Uncommitted 혹은 Dirty) 데이터 B를 읽을 수 있다.
  • READ_COMMITED(level 1)
    • 트랜잭션이 커밋 된 확정 데이터만 읽기 허용
    • 어떠한 사용자가 A라는 데이터를 B라는 데이터로 변경하는 동안 다른 사용자는 해당 데이터에 접근할 수 없다. 
    • Dirty Read 방지
  • REPEATABLE_READ(level 2)
    • 트랜잭션이 완료될 떄까지 SELECT 문장이 사용하는 모든 데이터에 Shared Lock이 걸리므로 다른 사용자는 그 영역에 해당되는 데이터에 대한 수정이 불가능하다.
    • 선행 트랜잭션이 읽은 데이터는 트랜잭션이 종료될 때까지 후행 트랜잭션이 갱신하거나 삭제가 불가능 하기 떄문에 같은 데이터를 두 번 쿼리했을 때 일관성 있는 결과를 리턴한다.
    • Non-Repeatable Read 방지
  • SERIALIZABLE(level 3)
    • 데이터의 일관성 및 동시성을 위해 MVCC(Multi Version Concurrency Control)을 사용하지 않음 
    • 트랜잭션이 완료될 때까지 SELECT 문장이 사용하는 모든 데이터에 Shared lock이 걸리므로 다른 사용자는 그 영역에 해당되는 데이터에 대한 수정 및 입력이 불가능하다.
    • Phantom Read 방지
참고

MVCC

MVCC는 다중 사용자 데이터베이스 성능을 위한 기술로 데이터 조회 시 LOCK을 사용하지 않고 데이터의 버전을 관리해 데이터의 일관성 및 동시성을 높이는 기술

 

 

Propagation (전파 옵션)

트랜잭션 동작 도중 다른 트랜잭션을 호출(실행)하는 상황에 선택할 수 있는 옵션

  • REQUIRED
    • 디폴트 속성, 부모 트랜잭션 내에서 실행하며 부모 트랜잭션이 없는 경우 새로운 트랜잭션을 생성한다.
  • SUPPORTS
    • 이미 시작된 트랜잭션이 있으면 참여하고 그렇지 않으면 트랜잭션 없이 진행하게 만든다.
  • REQUIRES_NEW
    • 부모 트랜잭션을 무시하고 무조건 새로운 트랜잭션이 생성
  • MANDATORY
    • REQUIRED와 비슷하게 이미 시작된 트랜잭션이 있으면 참여한다.
    • 반면 트랜잭션이 시작된 것이 없으면 새로 시작하는 대신 예외를 발생
  • NOT_SUPPORTED
    • 트랜잭션을 사용하지 않게 한다.
    • 이미 진행 중인 트랜잭션이 있으면 보류시킨다.
  • NEVER
    • 트랜잭션을 사용하지 않도록 강제한다.
  • NESTED
    • 이미 진행중인 트랜잭션이 있으면 중첩 트랜잭션을 시작
    • 중첩 트랜잭션은 트랜잭션 안에 다시 트랜잭션을 만드는 것이다.

 

중첩된 트랜잭션은 먼저 시작된 부모 트랜잭션의 커밋과 롤백에는 영향을 받지만 자신의 커밋과 롤백은 부모 트랜잭션에게 영향을 주지 않는다.

 

 

Read Only 

  • 트랜잭션을 읽기 전용으로 설정할 수 있다.
  • 성능을 최적화하기 위해 사용할 수 도있 있고 특정 트랜잭션 작업 안에서 쓰기 작업이 일어나는 것을 의도적으로 방지하기 위해 사용 할 수도 있다.
  • 일반적으로 읽기 전용 트랜잭션이 시작된 이후 INSERT, UPDATE, DELETE  같은 쓰기 작업이 진행되면 예외 발생

 

 

트랜잭션 롤백 예외

RollbackFor

특정 예외가 발생시 강제로 Rollback

@Transactional(rollbackFor=Exception.class)

 

noRollbackFor

특정 예외의 발생 시 Rollback 처리되지 않음

@Transactional(noRollbackFor=Exception.class)

 

 

TimeOut 속성

지정한 시간 내에 해당 메소드 수행이 완료되지 않는 경우 rollback 수행 

 

긴 글 읽어 주셔서 감사합니다.
반응형