본문 바로가기

프로그래밍/Spring

[Spring] @Transactional

@Transactional이란

 스프링에서 트랜잭션처리하는 방법 중 하나로, 어노테이션을 활용한 선언적 트랜잭션이라 한다.

여기서 트랜잭션이란 DB의 값을 변경하는 일련의 작업들을 하나의 처리로 묶어 반영(Commit)시키거나 취소(RollBack)시키는 것을 의미한다.

 

트랜잭션 옵션

1. isolation (격리레벨)

 - 트랜잭션에서 일관성 없는 데이터 허용 수준을 설정한다.

 

 적용방법

@Transactional(isolation=Isolation.DEFAULT)
public void addUser(UserDTO dto) throws Exception {
	// 로직 구현
}
  • DEFAULT : 기본 격리 수준
    = 기본이며, DB의 Isolation Level을 따른다.

  • READ_UNCOMMITED (level 0) : 커밋되지 않는 데이터에 대한 읽기를 허용
    = 어떤 사용자가 A라는 데이터를 B라는 데이터로 변경하는 동안 다른 사용자는 B라는 아직 완료되지 않은 (Uncommitted 혹은 Dirty)데이터 B를 읽을 수 있다.
    -Problem1 - Dirty Read 발생

  • READ_COMMITED (level 1) : 커밋된 데이터에 대해 읽기 허용
    = 어떠한 사용자가 A라는 데이터를 B라는 데이터로 변경하는 동안 다른 사용자는 해당 데이터에 접근할 수 없다.
    -Problem1 - Dirty Read 방지

  • REPEATABLE_READ (level 2) : 동일 필드에 대해 다중 접근 시 모두 동일한 결과를 보장
    = 트랜잭션이 완료 될 때 까지 SELECT 문장이 사용하는 모든 데이터에 shared lock이 걸리므로 다른 사용자는 그 영역에 해당되는 데이터에 대한 수정이 불가능하다.
    = 선행 트랜잭션이 읽은 데이터는 트랜잭션이 종료될 때까지 후행 트랜잭션이 갱신하거나 삭제가 불가능 하기 때문에 같은 데이터를 두 번 쿼리했을 때 일관성있는 결과를 리턴한다.
    -Problem2 - Non-Repeatable Read 방지

  • SERIALIZABLE (level 3) : 가장 높은 격리, 성능 저하의 우려가 있음
    = 데이터의 일관성 및 동시성을 위해 MVCC(Multi Version Concurrency Control)을 사용하지 않음.
    (MVCC는 다중 사용자 데이터베이스 성능을 위한 기술로 데이터 조회 시 LOCK을 사용하지 않고 데이터의 버전을 관리해 데이터의 일관성 및 동시성을 높이는 기술)
    = 트랜잭션이 완료될 때까지 SELECT 문장이 사용하는 모든 데이터에 shared lock이 걸리므로 다른 사용자는 그 영역에 해당되는 데이터에 대한 수정 및 입력이 불가능하다.
    -Problem3 - Phantom Read 방지

 

2. propagation (전파속성)

 - 트랜잭션 동작 도중 다른 트랜잭션을 호출할 때, 어떻게 할 것인지 지정하는 옵션이다.

 

적용방법

@Transactional(propagation=Propagation.REQUIRED)
public void addUser(UserDTO dto) throws Exception {
	// 로직 구현
}
  • REQUIRED (Default)
    이미 진행중인 트랜잭션이 있다면 해당 트랜잭션 속성을 따르고, 진행중이 아니라면 새로운 트랜잭션을 생성한다.

  • REQUIRES_NEW
    항상 새로운 트랜잭션을 생성한다. 이미 진행중인 트랜잭션이 있다면 잠깐 보류하고 해당 트랜잭션 작업을 먼저 진행한다.

  • SUPPORT
    이미 진행중인 트랜잭션이 있다면 해당 트랜잭션 속성을 따르고, 없다면 트랜잭션을 설정하지 않는다.

  • NOT_SUPPORT
    이미 진행중인 트랜잭션이 있다면 보류하고, 트랜잭션 없이 작업을 수행한다.

  • MANDATORY
    이미 진행중인 트랜잭션이 있어야만 작업을 수행한다. 없다면 Exception을 발생시킨다.

  • NEVER
    트랜잭션이 진행중이지 않을 때 작업을 수행한다. 트랜잭션이 있다면 Exception을 발생시킨다.

  • NESTED
    진행중인 트랜잭션이 있다면 중첩된 트랜잭션이 실행되며, 존재하지 않으면 REQUIRED와 동일하게 실행된다.

 

3. noRollbackFor (예외무시)

 - 특정 예외 발생 시 rollback하지 않는다.

 

적용방법

@Transactional(noRollbackFor=Exception.class)
public void addUser(UserDTO dto) throws Exception {
	// 로직 구현
}

 

4. rollbackFor (예외추가)

 - 특정 예외 발생 시 rollback한다.

 

적용방법

@Transactional(rollbackFor=Exception.class)
public void addUser(UserDTO dto) throws Exception {
	// 로직 구현
}

 

5. timeout (시간지정)

 - 지정한 시간 내에 메소드 수행이 완료되지 않으면 rollback 한다. (-1일 경우 timeout을 사용하지 않는다.)

 default = -1

 

적용방법

@Transactional(timeout=10)
public void addUser(UserDTO dto) throws Exception {
	// 로직 구현
}

 

6. readOnly (읽기전용)

 - 트랜잭션을 읽기 전용으로 설정한다.

 default = false,

 true시 insert, update, delete 실행 시 예외 발생

적용방법

@Transactional(readonly = true)
public void addUser(UserDTO dto) throws Exception {
	// 로직 구현
}