본문 바로가기
  • 실행력이 모든걸 결정한다
Spring Series/Spring Framework

[Spring] @Transactional의 속성

by 김코더 김주역 2022. 7. 9.
반응형

@Transactional은 Fallback 정책을 통해서 특정 트랜잭션 속성을 적용할 대상을 매우 유연하게 선정할 수 있도록 하는 어노테이션이다. Fallback 정책은 @Transactional 어노테이션의 작성 위치에 따른 설정의 우선순위를 다르게 적용하는 것이다.

타깃 메소드 > 타깃 클래스 > 선언 메소드 > 선언 타입

※ 여기에서 선언은 인터페이스처럼 선언만 하고 구현하지 않은 대상을 뜻한다.

 

트랜잭션의 구조 및 속성은 다음과 같다.

@Target({ElementType.TYPE, ElementType.METHOD}) // 어노테이션 사용대상 지정
@Retention(RetentionPolicy.RUNTIME) // 어노테이션의 정보유지 기간 
@Inherited
@Documented
public @interface Transactional {

	@AliasFor("transactionManager")
	String value() default "";
    
	@AliasFor("value")
	String transactionManager() default "";
	
	String[] label() default {};
	
	Propagation propagation() default Propagation.REQUIRED;

	Isolation isolation() default Isolation.DEFAULT;

	int timeout() default TransactionDefinition.TIMEOUT_DEFAULT;

	String timeoutString() default "";

	boolean readOnly() default false;

	Class<? extends Throwable>[] rollbackFor() default {};

	String[] rollbackForClassName() default {};

	Class<? extends Throwable>[] noRollbackFor() default {};

	String[] noRollbackForClassName() default {};
}

 

일부 트랜잭션 매니저에서는 일부 속성을 지원하지 않을 수 있기 때문에, 트랜잭션의 속성은 각 트랜잭션 매니저에 대해 잘 공부하고 사용하는 것을 권장한다.

이제 각 속성이 의미하는 바와 지정할 수 있는 속성값에는 무엇이 있는지 살펴보자. 

 

 

1. propagation

- 트랜잭션의 전파 속성을 의미한다. org.springframework.transaction.annotation.Propagation에 정의된 이늄 값을 사용하며, 기본값은 Propagation.REQUIRED이다.

 

(1) Propagation.REQUIRED

- 기본값 속성으로, 보통은 이 속성으로 충분하다.

- 진행 중인 트랜잭션이 있으면 이에 참여하고 그렇지 않으면 트랜잭션을 새로 시작한다.

- 하나의 트랜잭션이라도 문제가 발생하면 전체를 rollback 한다.

 

(2) Propagation.SUPPORTS

- 진행 중인 트랜잭션이 있으면 이에 참여하고 그렇지 않으면 트랜잭션 없이 독립적으로 실행한다.

- 트랜잭션이 없더라도 해당 경계 안에서 Connection이나 Hibernate Session 등을 공유할 수 있다.

 

(3) Propagation.MANDATORY

- 진행 중인 트랜잭션이 있으면 이에 참여하고 그렇지 않으면 예외를 발생시킨다.

- 독립적으로 트랜잭션을 진행하면 안되는 경우에 사용할 수 있다.

 

(4) Propagation.REQUIRED_NEW

- 항상 새로운 트랜잭션을 시작한다.

- 진행 중인 트랜잭션이 있으면 보류한다.

 

(5) Propagation.NOT_SUPPORTED

- 트랜잭션을 적용하지 않는다.

- 진행 중인 트랜잭션이 있으면 보류한다.

 

(6) Propagation.MANDATORY

- 트랜잭션을 적용하지 않는다.

- 진행 중인 트랜잭션이 있다면 예외를 발생시킨다.

 

(7) Propagation.NESTED

- 이미 진행 중인 트랜잭션이 있으면 중첩 트랜잭션을 시작한다. 즉, 트랜잭션 안에 다시 트랜잭션이 만들어진다.

- 중첩된 트랜잭션은 부모 트랜잭션에 영향을 받지만 부모 트랜잭션에 영향을 주진 않는다.

- 작업이 실패하더라도 메인 작업의 트랜잭션까지 롤백할 필요는 없을 때 사용할 수 있다.

- 중첩 트랜잭션을 지원하는 드라이버, 트랜잭션 매니저를 이용할 때 적용 가능하다.

 

 

2. isolation

- 트랜잭션의 격리 수준이다. 동시에 여러 트랜잭션이 진행될 때 트랜잭션 작업 결과를 다른 트랜잭션에게 어떻게 노출할지를 결정하는 속성이다.

- org.springframework.transaction.annotation.Isolation에 정의된 이늄값을 사용하며, 기본값은 Isolation.DEFAULT이다.

 

1) DEFAULT

- DB의 기본 격리 수준을 따른다. 대부분의 DB는 READ_COMMITTED를 기본 격리 수준으로 갖는다.

 

2) READ_UNCOMMITTED

- 가장 낮은 격리 수준으로, 하나의 트랜잭션이 커밋되기 전에 그 변화가 다른 트랜잭션에 노출된다.

※ 이처럼 하나의 트랜잭션이 커밋되기 전에 그 변화가 다른 트랜잭션에 노출되는 문제를 Dirty Read라고 한다.

- 데이터의 일관성은 떨어지더라도 속도는 매우 빠르다.

 

3) READ_COMMITTED

- 하나의 트랜잭션이 아직 커밋되지 않았다면 다른 트랜잭션에 그 변화가 노출되지 않는다.

- 하나의 트랜잭션이 읽은 row가 도중에 커밋한 다른 트랜잭션에 의해 수정될 수 있다.

※ 이처럼 같은 행을 두 번 이상 조회했을 때 값이 달라지는 문제를 Non-repeatable Read라고 한다.

- 실제로 가장 많이 사용되는 격리 수준이다.

 

4) REPEATABLE_READ

- 하나의 트랜잭션이 읽은 row가 도중에 다른 트랜잭션에 의해 수정되는 것을 막아준다.

- 새로운 row가 추가되는 것 까지는 막지 못한다.

※ 이처럼 반복 조회 시 결과 집합이 달라지는 것을 Phantom Read라고 한다.

 

5) SERIALIZABLE

- 가장 강력한 격리 수준으로, 트랜잭션을 순차적으로 진행시킨다. 즉, 여러 트랜잭션이 동시에 같은 테이블에 접근하지 못하게 막는다.

- 가장 안전하지만 성능이 떨어진다.

 

 

3. timeout

- 트랜잭션에 제한시간을 지정하는 속성이다. 단위는 초(s)로, 보통은 트랜잭션 시스템의 제한 시간을 따른다.

 

 

4. readOnly

- 트랜잭션을 읽기전용으로 설정하는 속성으로, 기본값은 false다.

- 쓰기 작업(INSERT, UPDATE, DELETE)을 방지할 수 있고, 성능도 좋아진다.

- 보통 get, find로 시작하는 메소드에 적용된다.

 

 

5. rollbackFor, rollbackForClassName

- 체크 예외지만 rollback 대상으로 삼아야 하는 예외를 지정하는 속성이다.

※ 선언적 트랜잭션에서는 런타임 예외가 발생하면 rollback하고, 체크 예외가 발생하면 commit한다는 특징이 있다. Spring에서는 데이터 엑세스 기술에 대한 예외를 런타임 예외로 전환해주기 때문에 런타임 예외를 rollback 하는 것이다.

- rollbackFor에는 예외 클래스(.class)를 지정하고, rollbackForClassName에는 예외 클래스의 이름을 지정한다. 

 

 

6. noRollbackFor, noRollbackForClassName

- 런타임 예외지만 commit 대상으로 삼아야 하는 예외를 지정하는 속성이다.

- noRollbackFor에는 예외 클래스(.class)를 지정하고, noRollbackForClassName에는 예외 클래스의 이름을 지정한다. 

 

 

 

 

 

 

 

● 참고 자료 : 토비의 스프링 3.1 Vol.2

 

반응형

댓글