[Database] Transaction

dustle·2023년 8월 23일
1

Transaction 은 데이터베이스의 상태를 변화시키기 위해 수행되는 작업 단위입니다.

1. ACID 원칙

데이터베이스 트랜잭션이 안전하게 수행된다는 것을 보장하기 위한 성질을 가리키는 약어입니다.

  • atomicity(원자성) : 한 트랜잭션 내에서 실행한 작업은 하나로 간주합니다. (다 성공 아니면 실패)
  • consistency(일관성) : 트랜잭션은 일관성 있는 데이터베이스 상태를 유지해야합니다.
  • isolation(격리성) : 동시에 실행되는 트랜잭션이 영향을 미치지 않아야합니다.
  • durability(지속성) : 트랜잭션을 성공적으로 마치면 저장이 되어야합니다.

2. 트랜잭션 격리수준

트랜잭션의 격리 수준(Isolation Level)이란 여러 트랜잭션이 동시에 처리될 때,
특정 트랜잭션이 다른 트랜잭션에서 변경하거나 조회하는 데이터를 볼 수 있게 허용할지 여부를 결정하는 것입니다. 트랜잭션의 격리 수준은 격리수준이 높은 순서대로
SERIALIZABLE, REPEATABLE READ, READ COMMITTED, READ UNCOMMITED 가 존재합니다.

  • READ UNCOMMITED : 커밋되지 않은 데이터를 다른 트랜잭션에서 접근 할 수 있습니다.
    하지만 DirtyRead가 가능하기 때문에 잘못된 데이터를 읽을 수 있습니다.
    DirtyRead - DB에 커밋하지 않은 존재하지 않은 데이터를 읽는 현상

    • A 트랜잭션이 데이터 1 을 조회하여 2 로 변경하고 아직 커밋하지 않음
    • B 트랜잭션이 동일한 데이터를 조회해서 2 라는 값을 받음 (Dirty Read)
    • A 트랜잭션에서 오류가 발생해서 데이터를 롤백 (2 -> 1)
    • 실제 데이터는 1 이지만 B 트랜잭션은 2 라는 잘못된 데이터를 읽은 셈

  • READ COMMITTED : 커밋한 데이터만 읽을 수 있습니다.
    Non-Repeatble Read가 발생할 수 있습니다.
    트랜잭션에서 조회한 데이터가 트랜잭션이 끝나기 전에 다른 트랜잭션에 의해 변경되면 다시 읽었을 때 새로운 값이 읽히며 데이터 불일치하는 현상을 말합니다.

    하나의 트랜잭션 내에서 똑같은 SELECT 쿼리를 실행했을 때 항상 같은 결과를 가져와야 한다는 REPEATABLE READ 정합성 정의에 어긋납니다.

    • A 트랜잭션이 데이터 (row) 를 읽음
    • B 트랜잭션이 같은 데이터를 수정하고 커밋
    • A 트랜잭션이 다시 같은 데이터를 읽었는데 데이터가 달라짐

  • REPEATABLE READ : 하나의 트랜잭션은 하나의 스냅샷만 사용할 수 있습니다.
    MySQL에서 사용하고 있는 트랜잭션 격리 수준입니다.
    Phantom Read라는 다른 트랜잭션에서 수행한 작업에 의해 안보이던 데이터가 보일 수 있습니다.
    repeatable_read 격리 수준은 조회한 데이터에 대해서만 Shared Lock 이 걸리기 때문에 다른 트랜잭션이 새로운 데이터를 추가할 수 있습니다.

  • SERIALIZABLE : 순차적으로 트랜잭션을 실행하여 읽기 작업에도 잠금을 겁니다.
    가장 안전하지만 성능이 저하됩니다.

3. Propagation

Spring 이 제공하는 @Transactional 은 여러 트랜잭션을 묶어서 하나의 트랜잭션 경계를 만들 수 있습니다.
하지만 기존의 트랜잭션이 진행 중일 때 추가적인 트랜잭션을 사용해야 할 경우가 생길 수 있습니다
추가 트랜잭션을 어떻게 진행할지 결정하는 것이 전파 속성 입니다.

  • REQUIRED :
    • 기본 옵션
    • 부모 트랜잭션이 존재한다면 부모 트랜잭션에 합류, 그렇지 않다면 새로운 트랜잭션을 만듭니다.
    • 중간에 자식/부모에서 rollback이 발생된다면 자식과 부모 모두 rollback 합니다.

  • REQUIRES_NEW :
    • 무조건 새로운 트랜잭션을 만듭니다.
    • nested한 방식으로 메소드 호출이 이루어지더라도 rollback은 각각 이루어 집니다.

  • NAMDATORY :
    • 무조건 부모 트랜잭션에 합류시킵니다.
    • 부모 트랜잭션이 존재하지 않는다면 예외를 발생시킵니다.

  • SUPPORTS :
    • 메소드가 트랜잭션을 필요로 하지는 않지만, 진행 중인 트랜잭션이 존재하면 트랜잭션을 사용한다는 것 을 의미합니다.
    • 진행 중인 트랜잭션이 존재하지 않더라도 메소드는 정상적으로 동작합니다.

  • NESTED :
    • 부모 트랜잭션이 존재하면 부모 트랜잭션에 중첩시키고, 부모 트랜잭션이 존재하지 않는다면 새로운 트랜잭션을 생성합니다.
    • 부모 트랜잭션에 예외가 발생하면 자식 트랜잭션도 rollback 합니다.
    • 자식 트랜잭션에 예외가 발생하더라도 부모 트랜잭션은 rollback하지 안습니다.
    • 이때 롤백은 부모 트랜잭션에서 자식 트랜잭션을 호출하는 지점까지만 롤백됩니다.
    • 이후 부모 트랜잭션에서 문제가 없으면 부모 트랜잭션은 끝까지 commit 됩니다.
    • 현재 트랜잭션이 있으면 중첩 트랜잭션 내에서 실행하고, 그렇지 않으면 REQUIRED 처럼 동작합니다.

  • NEVER :
    • 메소드가 트랜잭션을 필요로 하지 않습니다.
    • 만약 진행 중인 트랜잭션이 존재하면 익셉션이 발생합니다.

0개의 댓글