2016년 5월 3일 화요일

Spring Transaction의 Propagation과 Isolation에 대해..

참고 : http://stackoverflow.com/questions/8490852/spring-transactional-isolation-propagation , http://www.byteslounge.com/tutorials/spring-transaction-propagation-tutorial , http://www.byteslounge.com/tutorials/spring-transaction-isolation-tutorial

헷갈릴 땐 라이브러리의 소스코드의 각 타입별 주석을 참고해도 되지만 이참에 정리하자 싶어서 작성합니다. Transactional 어노테이션의 propagation과 isolation 항목에 대한 설정 정보에 대해 알아보도록 하겠습니다.

PROPAGATION

비지니스 메소드가 호출될 때 자기 자신과 내부에서 호출 된 Transaction(이하 tx)간에 어떻게 상호 작용할 것인지에 대한 상태를 정의 하는 항목으로 다음과 같은 설정들이 존재 합니다.
  • REQUIRED : 해당 상태가 선언된 메소드가 실행 될 때 tx가 존재 한다면 공유해서 사용하고 그렇지 않다면 새 tx를 생성해서 사용합니다. 만약 내부에서 호출 된 메소드가 자신과 마찬가지로 REQUIRED가 선언된 상태라면 자신과 내부 tx각각은 논리적으로는 구분 되지만 물리적으로는 하나의 tx가 됩니다. 내부에서 호출 된 메소드의 tx가 롤백 된다면 자신을 포함한 물리적인 하나의 tx가 롤백 되는 구조를 만들 수 있습니다.
  • REQUIRES_NEW : 해당 상태가 선언된 메소드가 실행될 때 항상 새로운 물리적인 tx를 생성하고 해당 tx가 롤백 된다고해서 물리적으로 분리된 다른 tx가 롤백 되지는 않습니다. 만약 내부적으로 새로운 tx가 시작 된다면 자신의 tx는 잠시 정지 되었다가 내부 tx가 종료된 시점에 이어서 수행되게 됩니다.
  • NESTED : 자신과 내부 tx들이 하나의 물리적인 tx를 사용하지만 내부에서 호출된 NESTED tx들에 savepoint를 세팅하는 형태 입니다. 그렇기 때문에 내부의 NESTED tx중 하나가 롤백이 된다고 하더라도 자신이 롤백 되지는 않습니다. 이 기능은 JDBC savepoint를 통해 구현되기 때문에 Spring JDBC로 관리되는 tx를 사용할때만 써야 합니다.
  • MANDATORY : 해당 상태가 호출될 때 열려있는 tx가 반드시 존재해야하며 그렇지 않으면 컨테이너에서 예외를 던집니다.
  • NEVER : 해당 상태가 호출될 때 열려있는 tx가 반드시 존재하지 않아야 하며 그렇지 않으면 컨테이너에서 예외를 던집니다.
  • NOT_SUPPORTED : 해당 상태는 tx의 범위에 포함되지 않는 것을 수행합니다. 만약 열려있는 tx가 존재 한다면 해당 tx를 잠시 멈추고 작업을 수행합니다.
  • SUPPORTS : 열려있는 tx가 이미 존재한다면 해당 tx에 포함되어 수행되며 만약 열려있는 tx가 존재하지 않더라도 수행은 되지만 tx와 관계없이 처리 됩니다.
주의할 점들..
  • 기본적으로 tx을 롤백 상태로 만들기 위해서는 unchecked exceptions를 필요로 하며 checked exceptions를 이용하기 위해서는 별도의 설정이 필요합니다.
  • Transactional 어노테이션만 선언된 메소드(Declarative transactions)에서 동일한 Bean 내부의 다른 메소드를 직접 호출할 경우(Self-invocation) 컨테이너에 의해 Transactional 선언이 무시되기 때문에 이경우는 aspectj를 사용해서 구성해야 합니다.
ISOLATION

ACID tx 요소 중 isolation 레벨에 대한 설정으로 특정 위치의 데이터에 대해 동시 다수의 tx가 존재 할 때 해당 데이터에 어떻게 접근할 것인지에 대해 정의할 수 있습니다.
  • READ_UNCOMMITTED : 여러 tx가 동시에 x라는 데이터에 접근 할 때 x에 변경이 일어난 시점과 읽는 시점에 따라 롤백 여부와 상관없이 변경된 값을 읽는 더티 리드(dirty reads)를 허용하는 상태입니다.
  • READ_COMMITTED : 더티 리드의 문제는 없지만 동시에 x라는 데이터에 접근할 때 타임라인 상 A라는 tx에서 x를 읽은 후 tx가 종료 되기 전에 B라는 tx에서 x를 변경후 커밋을 하게 될 경우 A에서 x를 다시 읽는 케이스가 존재 한다면 처음 읽은 x의 값과 나중에 읽은 x의 값이 다른 문제(non-repeatable reads)가 발생하게 됩니다.
  • REPEATABLE_READ : 하나의 tx에서 단일 레코드를 여러번 읽는 경우 결과가 항상 같아야 하는 상태이며 dirty reads와 non-repeatable reads 문제를 제거할 수 있습니다. 하지만 범위 스캔을 하는 경우 tx A에서 범위의 조건이 0-20 사이의 값을 읽고 tx A가 종료되기 전에 tx B에서 0-20사이에 레코드를 추가하게 된다면 tx A에서 0-20 사이의 값을 다시 읽었을 때 tx B에서 추가한 레코드(phantom records)가 포함되는 팬텀 리드(phantom reads)의 문제가 있습니다.
  • SERIALIZABLE : 가장 제한적인 상태이며 읽기, 범위 스캔, 쓰기에 tx락을 거는 형태입니다. 앞서 언급한 모든 문제를 해결할 수 있지만 tx의 동시성을 허용하지 않아 퍼포먼스 패널티를 지속적으로 증가시키는 문제가 있습니다.
  • DEFAULT : DBMS에서 정의된 Default Isolation 레벨에 대한 상태를 적용합니다.
각 isolation 레벨이 갖는 문제를 요약하면 다음과 같습니다.
  • READ_UNCOMMITTED : dirty reads, non-repeatable reads, phantom reads
  • READ_COMMITTED : non-repeatable reads, phantom reads
  • REPEATABLE_READ : phantom reads

댓글 없음:

댓글 쓰기