[Spring] 트랜잭션 이란?

rara_kim·2022년 9월 5일
0

Spring

목록 보기
10/20

트랜잭션(Transaction)

데이터베이스의 상태를 변화시키기 위해 수행하는 작업 단위를 말한다.
여기서 말하는 작업 단위는 프로젝트 별, 상황 별로 정의하기 나름이다.

예를 들어,  트랜잭션: 오늘 일기 작성하기...
(1)오늘 날씨 데이터를 가져와서,  (2)일기를 DB에 저장하기
(1)과 (2)를 모두 수행해야 데이터베이스의 상태가 변화하므로, (1) + (2)를 하나의 트랜잭션이라고 본다.

트랜잭션을 이루는 속성

  • 원자성(Atomicity) : 트랜잭션이 모두 DB에 반영되거나, 모두 반영되지 않는 것. (1 또는 0)
  • 일관성(Consistency) : 트랜잭션의 작업 결과는 일관성이 있어야 한다.
  • 독립성(Isolation) : 각각의 트랜잭션은 독립적으로 수행되어야 한다.
  • 지속성(Durability) : 트랜잭션이 성공적으로 완료되었다면 변화된 상태가 지속적으로 반영되어야 한다.

트랜잭션의 연산

  • 커밋(Commit) : 트랜잭션이 성공적으로 완료되었다면 마지막으로 수정사항을 반영하기 위해 커밋을 한다.
  • 롤백(Rollback) :  트랜잭션이 정상적으로 완료되지 않은 경우, 트랜잭션을 실행하기 이전의 상태로 되돌리는 것이다. (트랜잭션을 구성하는 세부작업 모두 취소)

여러 트랜잭션이 경쟁을 하게 되면?

1. Dirty Read

  • 트랜잭션A : Test 테이블의 3번째 row 수정중
  • 트랜잭션B : Test 테이블의 3번째 row 조회하려 함

트랜잭션A가 데이터를 1에서 2로 수정하고 커밋을 하기 전에 트랜잭션B가 데이터를 조회하면, 트랜잭션B는 데이터를 2로 인식하게 될 것이다.
하지만, 트랜잭션A가 그 상태에서 커밋되지 않고 롤백되었다면 데이터는 다시 1이 될 것이다.
이런 경우 트랜잭션B는 잘못된 데이터를 읽어가게 된다.

2. Non-Repeatable Read

  • 트랜잭션A : Test 테이블의 3번째 row 조회 * 2
  • 트랜잭션B : Test 테이블의 3번째 row 수정 후 커밋

트랜잭션A가 데이터를 조회하고 다시 한번 조회하기 전에(두번의 조회 사이에) 트랜잭션B가 들어와 데이터를 수정후 커밋을 해버리게 되면 트랜잭션A가 두번째로 데이터를 조회했을 때 첫번째와 데이터 값이 달라지게 된다.
이렇게 되면 트랜잭션의 일관성을 만족시키지 못하게 된다.

3. Phantom Read

  • 트랜잭션A : Test 테이블의 0~4번째 row 조회 * 2
  • 트랜잭션B : Test 테이블의 3번째 row 수정 후 커밋

Non-Repeatable Read와 유사하게 트랜잭션A가 작업을 완료하기 전 트랜잭션B가 데이터를 수정, 커밋하여 일관성이 깨지게 된다.

💡Non-Repeatable Read : 특정 값을 두고 트랜잭션끼리 경쟁했을 때 발생하는 문제
    Phantom Read : 특정 범위 내의 값을 두고 트랜잭션끼리 경쟁했을 때 발생하는 문제


Spring에서의 트랜잭션

@Transactional

가장 일반적으로 사용하는 방법으로, 클래스메서드 위에 어노테이션을 추가할 수 있다.
트랜잭션 기능이 적용된 프록시 객체 생성이 가능하다.

  • PlatformTransaction Manager : 트랜잭션의 전체가 성공했는지, 혹은 예외가 있었는지 확인하여 Rollback 또는 Commit 작업을 해준다.
  • @EnableTransactionManagement 어노테이션을 같이 사용해야 Spring에서 정상적으로 작동한다.

Spring트랜잭션의 세부 설정들

트랜잭션을 철저하게 강제할 것인지 혹은 어떠한 제약조건을 줄 것인지 설정할 수 있다.

1. Isolation(격리수준)

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

  • DEFAULT : 사용하는 DB의 기본 Isolation을 따른다.
  • READ_UNCOMMITTED : Level0, 커밋되기 전에도 READ 가능 (Dirty Read 발생)
  • READ_COMMITTED : Level1, 커밋된 확정된 데이터만 READ 허용 (Dirty Read 방지)
  • REPEATABLE_READ : Level2, 트랜잭션 전체가 완료되기 전까지 다른 트랜잭션이 해당 데이터에 락이 걸려 조회할 수 없다. (Non-Repeatable Read 방지)
  • SERIALIZABLE : Level3, 트랜잭션이 완료되기 전까지 모든 데이터에 락이 걸린다. (Phantom Read 방지)
@Transactional(isolation=Isolation.DEFAULT)

2. Propagation(전파수준)

트랜잭션 동작 도중 다른 트랜잭션을 호출하는 상황에서 트랜잭션을 시작하거나 기존 트랜잭션에 참여하는 방법에 대해 결정하는 속성값. (함수A에서 함수B를 호출하는 경우)

  • REQUIRED : 디폴트 속성.
  • SUPPORTS : 이미 시작된 부모 트랜잭션이 있으면 그 트랜잭션에 참여하고, 그렇지 않으면 트랜잭션 없이 실행하는 옵션.
  • REQUIRES_NEW : 부모 트랜잭션 안에서 함수B가 호출되더라도 그냥 자기만의 트랜잭션을 생성하여 동작하는 방식.
  • NESTED : 이미 진행중인 트랜잭션이 있는 경우 중첩 트랜잭션을 생성하는 방식. 부모 트랜잭션이 롤백 혹은 커밋을 하더라도 자식 트랜잭션에는 영향이 없지만, 자식 트랜잭션의 결과는 부모 트랜잭션에게 영향을 준다.

    💡NESTED 사용 예시
     ex) 일기 작성 관련해서 로그를 DB에 저장하는 상황

     1. 로그 저장이 실패한다고 해서  ->  일기 작성까지 롤백되면 안됨
     2. 일기 작성이 실패한다면  ->  로그 작성까지 롤백 되어야 함

3. ReadOnly 속성

트랜잭션을 읽기 전용 속성으로 지정할 수 있는 속성.
성능을 최적화 하기 위해서도 사용되지만, 어떤 트랜잭션에서 읽기 외에 쓰기,삭제,수정을 의도적으로 방지하기 위해서도 사용된다.
ReadOnly 속성을 설정한 경우 읽기 외의 쿼리가 실행되면 예외가 발생한다.
기본 옶션은 false이므로 조회만 하는 로직의 경우 true로 설정하여 실수를 잡아줄 수도 있다.
또한, true의 경우 트랜잭션의 동작이 빨라진다.

@Transactional(readOnly=true)

4. 트랜잭션 롤백 예외

예외가 발생했을 때 트랜잭션을 롤백 시킬 경우를 설정하는 옵션.
특정 Exception에 대해서는 롤백하지 않고 진행하고자 하는 경우 사용할 수 있다.

@Transactional(rollbackFor=Exception.class)  -> 어떤 Exception이 발생하면 롤백한다.
@Transactional(noRollbackFor=Exception.class)  -> 어떤 Exception이 발생해도 커밋한다.

Default: RuntimeException, Error

5. timeout 속성

일정 시간 내에 트랜잭션을 끝내지 못하면 롤백하는 속성.
격리수준을 높여서 설정한 경우 timeout을 같이 설정하는 것이 좋다.

@Transactional(timeout=10)  ->  10초 안에 완료되지 않으면 롤백한다.

profile
느리더라도 꾸준하게

0개의 댓글