본문 바로가기

JAVA/Spring

[Spring] 스프링 트랜잭션과 동작방식에 대한 간략한 기록

728x90

스프링의 데이터베이스 처리 중 작동 방식에 대해 컨트롤할 수 있는 트랜잭션 기능을 제공합니다. 동작방식은 아래 4가지와 같습니다.

  • 전파: 로직 중 예외가 발생했을 때 예외까지 변경된 데이터가 되돌아가야(RollBack) 할지, 저장되어야 할지 (Commit)
  • 제한시간: 수행하는데 걸리는 시간을 설정
  • 격리수준: 실시간으로 수정 중인 다른 데이터를 조회했을 때 수정된 상태로 보여야 하는지, 트랜잭션 간의 작업의 연관성에 개입
  • 읽기전용: 데이터 조작을 방지

 

 

트랜잭션 전파 (PROPAGATION)

작업 A와 B가 있을 때 두 작업 간의 처리방식에 대한 설정입니다.

  1. PROPAGATION_REQUIRED
    1. A 작업이 수행된 후 B는 새로운 트랜잭션을 만들지 않고 A에 트랜잭션에 참여합니다.
    2. A와 B는 하나의 트랜잭션으로 묶여 둘 중 하나에서 예외가 발생하면 모두 취소됩니다.
  2. PROPAGATION_REQUIRES_NEW
    1. A와 B는 서로 무관한 트랜잭션으로 새로 생성하게 됩니다.
    2. 서로 독자적인 트랜잭션으로 하나의 트랜잭션이 수행되면 다른 트랜잭션에서 예외가 발생해도 이전 트랜잭션에 영향을 끼치지 않습니다.
  3. PROPAGATION_NOT_SUPPORTED
    1. 트랜잭션을 설정하지 않습니다.
    2. 단순 데이터 조회같은 트랜잭션이 필요없는 경우라면 이 속성을 사용할 수 있습니다.
  4. PROPAGATION_MANDATORY
    1. 기존 트랜잭션이 있다면 참여하고, 없다면 예외를 발생시킵니다.
    2. 혼자 트랜잭션을 진행시키면 안되는 로직에 사용할 수 있습니다.
  5. PROPAGATION_NESTED
    1. 기존 트랜잭션의 자식으로 생성합니다.
    2. REQUIRES_NEW와는 다르게 부모 트랜잭션의 예외는 자식 트랜잭션에 영향을 주지만 그 반대로 자식의 예외는 부모에게 영향을 주지 않습니다.
    3. 예를들어 자식 서비스의 로깅같은 트랜잭션이 있을 때 이가 실패되도 부모의 작업이 롤백되서는 안되므로 이 속성을 이용할 수 있습니다.

 

트랜잭션 격리수준 (ISOLATION)

모든 트랜잭션은 격리수준을 가지고 있습니다. 서비스에서 여러 트랜잭션이 동시에 진행될 수 있는데, 이 때 발생할 수 있는 데이터의 정합성 문제나 성능에 관여되는 트랜잭션 독립, 순차적인 레벨을 관리할 수 있습니다.

  1. ISOLATION_DEFAULT
    1. DB 드라이버의 기본 설정을 따릅니다.
    2. 대부분 READ_COMMITED를 기본 격리수준으로 가집니다.
    3. READ_COMMITED: 커밋된 것들만을 읽습니다.
  2. ISOLATION_READ_UNCOMMITTED
    1. 데이터 커밋 여부와 상관 없이 변경된 데이터를 읽어옵니다.
    2. 데이터의 정합성이 깨질 우려가 있습니다. (하나의 트랜잭션에서 같은 SELECT가 다른 결과를 가져올 수 있음)
    3. 가장 낮은격리수준이지만 가장 빠르기 때문에 성능이 중요한 상황에 사용합니다.
  3. ISOLATION_READ_COMMITTED
    1. 대부분 default 속성으로 지니며 가장 많이 사용됩니다.
    2. 트랜잭션이 이미 지나간 뒤 커밋이 완료된 내용만을 읽습니다.
    3. 이미 트랜잭션이 지나간 뒤 수정되어 순차가 다를 경우 처음 트랜잭션이 읽은 내용과 다를 수 있습니다.
  4. ISOLATION_REPEATABLE_READ
    1. 한번 읽은 트랜잭션이 수정되지 않도록 막아줍니다.
    2. 하지만 새로 insert하는 것을 막아주지 않습니다.
  5. SERIALIZABLE
    1. 가장 강력한 격리수준으로 트랜잭션을 순차적으로 진행시켜줍니다.
    2. 여러 트랜잭션이 동시에 같은 테이블의 정보를 엑세스할 수 없습니다.
    3. 성능이 안좋아 꼭 필요한 경우에만 사용합니다.

 

 

롤백/커밋 예외

추가적으로 롤백/커밋에 예외를 둘 수 있습니다.

  1. noRollbackFor: 특정 예외 발생 시 rollback하지 않는다.
  2. rollbackFor : 특정 예외 발생 시 rollback한다.

 

예시

@Transactional(noRollbackFor = { ExceptionA.class, ExceptionB.class })
	public void insertItem() {
	  ...
}