DB Transaction

HunkiKim·2022년 9월 21일
0

DB Transaction

하나의 논리적 기능을 수행하기 위한 작업의 단위로, DB의 일관된 상태를 또 다른 일관된 상태로 변환시키는 기능을 수행한다. 이 기능은 이름에서부터 알 수 있듯이 계좌 거래에서 유래됐다.

  • A에서 B계좌로 일정 금액을 이체한다고 하자.
    1. A 계좌의 잔액을 확인한다.
    2. A계좌의 금액에서 이체할 금액을 빼고 다시 저장한다.
    3. B계좌의 잔액을 확인한다.
    4. B계좌의 금액에서 이체할 금액을 더하고 다시 저장한다.
      이 과정을 모두 끝내고 DB를 업뎃하고 아니면 롤백하는게 트랜잭션이다.

즉 저 과정 모두 처리돼야만 성공하는 단일 작업이 있다고하자. 이를 DB에선 트랜잭션이라고 한다. 즉 아래와 같이 설명 된다.

  • 단일한 논리적인 작업 단위 (a single logical unit of work)
  • 논리적인 이유로 여러 SQL문들을 단일 작업으로 묶어서 나눠질 수 없게 만든 것이 transaction이다.
  • transaction의 SQL문들 중에 일부만 성공해서 DB에 반영되는 일은 일어나지 않는다.

보통 transaction을 시작하고 커밋할 때 까지의 작업을 한 단위로 본다. commit은 DB에 영구적으로 저장하라는 의미와 transaction의 종료를 하는 의미 두 가지가 기본이다.

사용 이유

  • 데이터베이스 관리 시스템은 데이터베이스가 항상 정확하고 일관된 상태를 유지할 수 있도록 다양한 기능을 제공하는데, 그 중심에 트랜잭션이 있다.
  • 트랜잭션은 데이터베이스에 장애 발생했을 때 복구 작업을 수행하거나, 다수의 사용자가 동시에 사용할 수 있도록 제어 작업을 하는 데 중요한 단위로 사용된다.
  • 트랜잭션을 관리함으로써 데이터베이스의 회복과 병행 제어가 가능해져 결과적으로 DB가 일관된 상태를 유지할 수 있게 된다.
  • 트랜잭션의 모든 명령문이 완벽하게 처리되거나 하나도 처리되지 않아야 데이터베이스가 모순없는 일관된 상태를 유지할 수 있다.

    DB의 무결성과 일관성을 보장하려면 작업을 수행하는 데 필요한 연산들을 하나의 트랜잭션으로 제대로 정의하고 관리해야 한다.

자바에서의 transaction

public void transfer(String formId, String told, int amount) {
  try {
    Connection connection = ..; 
    connection.setAutoCommit(false);
    ..
    ..
    connection.commit();
  } catch (Exception e) {
    ...
    connection.rollback();
  } finally {
    connection.setAutoCommit(true);
  }
}
  1. connection을 연결한다.
  2. connection의 오토커밋을 끈다. -> 트랜잭션 시작
  3. 하고싶은 로직들을 수행한다.
    1. 중간에 에러가 발생했다면 롤백한다.
  4. 정상적으로 로직이 완료되었다면 커밋(트랜잭션 종료)한다.
  5. 마지막으로 finally를 통해 다시 autocommit을 켜준다.

그리고 @Transactional 어노테이션을 이용하면 중간의 하고싶은 로직만 넣으면 된다. 아래와 같다.

public void transfer(String formId, String told, int amount) {

    ..
    ..
   
}

하고싶은 로직만 남는다.

특성 (ACID)

Atomicity (원자성)

  • 트랜잭션을 구성하는 연산들이 모두 정상적으로 실행되거나 하나도 실행되지 않아야 한다는 all-or-nothing방식을 의미한다.
  • 모두 성공하거나 모두 실패하거나
  • 만약 트랜잭션을 수행하다가 작업에 장애가 발생하면 실행한 연산들을 모두 취소하고 롤백하여 원자성을 보장한다.

Consistency (일관성)

  • 트랜잭션이 성공적으로 수행된 후에도 데이터베이스가 일관성 있는 상태를 유지하는 것이다.
  • 트랜잭션이 수행되기 전에 DB가 일관된 상태였다면 수행이 완료된 후에 결과를 반영한 DB도 또 다른 일관된 상태가 되어야 한다.
  • 트랜잭션이 수행되는 과정 중에는 DB가 일시적으로 일관된 상태가 아닐 수는 있지만 트랜잭션의 수행이 완료된 후에는 일관된 생태를 유지해야 한다.
  • 보통 트랜잭션이 DB에 정의된 rule을 위반했는지는 DBMS가 commit 전에 확인하고 알려준다.
  • 그 외에 application 관점에서 transaction이 consistent하게 동작하는지는 개발자가 챙겨야 한다. 예를들면 Exception처리를 잘 해서 롤백해주면 된다. @Transaction해주는 것도 개발자가 해주는 것이다.
  • 즉 한마디로 결과 이전과 이후의 데이터가 일관성있게 유지되어야 한다는 말이다.

Isolation (격리성)

  • 현재 수행 중인 트랜잭션이 완료될 때까지 트랜잭션이 생성한 중간 연산 결과에 다른 트랜잭션들이 접근할 수 없다.
    • 접근할 경우 동시성 문제가 발생한다.
  • 데이터베이스 시스템에서는 여러 트랜잭션이 동시에 수행되지만 각 트랜잭션이 독립적으로 수행될 수 있도록 다른 트랜잭션의 중간 연산 결과에 서로 접근하지 못하게 한다.
  • isolation level이 높을수록 성능이 줄어든다.
  • 이는 3가지 문제가 있다.
    • Dirty Read : Dirty Read는 다른 트랜잭션에 의해 수정됐지만 아직 커밋되지 않은 데이터를 읽는 것을 말한다. 예를 들어 2번키를 가진걸 인서트 하고 커밋을 안했는데 다른 트랜잭션에서 이 2번키 인서트값을 읽는 것을 말한다.
    • Non-Repeatable Read : 한 트랜잭션 내에서 같은 Key를 가진 Row를 두 번 읽었는데 그 사이에 값이 변경되거나 삭제되어 결과가 다르게 나타나는 현상을 말한다.예를들어 1번키 값을 SA로 읽었는데 다시 1번 키를 읽었는데 DA가 되어버리는 현상. 또는 삭제되서 볼 수 없는 경우이다.
    • Phantom Read : 한 트랜잭션 내에서 같은 쿼리를 두 번 수행했는데, 첫 번째 쿼리에서 없던 유령(Phantom)레코드가 두 번째 쿼리에서 나타나는 현상을 말한다. 예를 들면 첫 SELECT에선 1나만 있었는데 2번째 쿼리에선 2개가 있는 것이다.
  • 격리성에는 격리성 수준이 있다.
    • Read Uncommitted : 트랜잭션에서 처리 중인 아직 커밋되지 않은 데이터를 다른 트랜잭션이 읽는 것을 허용한다. 해당 수준에서는 Dirty Read, Non-Repeatable Read, Phantom Read가 일어날 수 있다.
    • Read Committed : 트랜잭션이 커밋되어 확정된 데이터만 다른 트랜잭션이 읽도록 허용한다. 따라서 Dirty Read의 발생 가능성을 막는다. 하지만 Non-Repeatable Read와 Phantom Read에 대해서는 발생 가능성이 있다.
    • Repeatable Read : 트랜잭션내에서 삭제, 변경에 대해서 Undo 로그에 넣어두고 앞서 발생한 트랜잭션에 대해서는 실제 데이터가 아닌 Undo 로그에 있는 백업 데이터를 읽게 한다.
    • Serializable Read : 트랜잭션 내에서 쿼리를 두 번 이상 수행할 때, 첫 번째 쿼리에 있던 레코드가 사라지거나 값이 바뀌지 않음은 몰론 새로운 레코드가 나타나지도 않도록 하는 설정이다.

Durability (지속성, 영존성)

  • 트랜잭션이 성공적으로 완료된 후 데이터베이스에 반영한 수행 결과는 어떠한 경우에도 손실되지 않고 영구적이어야 함을 의미한다.
  • 시스템에 장애가 발생하더라도 트랜잭션 작업 결과는 없어지지 않고 데이터베이스에 그대로 남아있어야 한다는 의미이다.
  • 트랜잭션의 지속성을 보장하려면 시스템에 장애가 발생했을 때 데이터베이스를 원래 상태로 복구하는 회복 기능이 필요하다.
  • 즉 커밋 끝나고 DB에 영구적으로 저장되어야 한다는 의미이다. 여기서 영구적이란 DB system에 문제(전원나감, DB충돌)가 생겨도 커밋된 트랜잭션은 DB에 남아있어야 한다.
    • 영구적으로 저장한다는 것은 일반적으로 비휘발성 메모리(HDD, SSD..와같은것)에 저장함을 의미한다.
  • 기본적으로 트랜잭션의 durability는 DBMS가 보장한다.

정리

  • 원자성 <- 회복 기능
  • 일관성 <- 병행 제어 기능
  • 격리성 <- 병행 제어 기능
  • 지속성 <- 회복 기능

트랜잭션의 연산

  • commit 연산 : 트랜잭션이 성공적으로 수행되었음을 선언 (작업 완료)
  • rollback 연산 : 트랜잭션이 수행을 실패했음을 선언 (작업 취소)

트랜잭션의 상태

트랜잭션은 다섯 가지 상태 중 하나에 속하게 된다.
1. 트랜잭션이 수행을 시작하면 활동 상태가 되고, 활동 상태의 트랜잭션이 마지막 연산을 처리하고 나면 부분 완료 상태, 부분 완료 상태의 트랜잭션이 commit 연산을 실행하면 완료 상태가 된다.
2. 활동 상태나 부분완료 상태에서 더는 정상적인 수행이 불가능하게 되면 트랜잭션은 실패 상태가 된다.
3. 실패 상태의 트랜잭션은 rollback 연산의 실행으로 철회 상태가 된다. 트랜잭션이 완료 상태이거나 철회상태가 되면 트랜잭션이 종료된 것으로 판단한다.

활동 상태(active)

  • 트랜잭션이 수행을 시작하여 현재 수행 중인 상태이다.
  • 활동 상태인 트랜잭션은 상황에 따라 부분 완료 상태나 실패 상태 중 하나이다.

부분 완료 상태(partially committed)

  • 트랜잭션의 마지막 연산이 실행된 직후의 상태이다.
  • 이는 트랜잭션의 모든 연산을 처리한 상태이다.
  • 트랜잭션이 수행한 최종 결과를 데이터베이스에 아직 반영하지 않은 상태이다.
  • 이는 아직 완료됐다고 볼 수 없다.

완료 상태(committed)

  • 트랜잭션이 성공적으로 완료되어 commit 연산을 실행한 상태이다.
  • 트랜잭션이 수행한 최종 결과를 데이터베이스에 반영하고, 데이터베이스가 새로운 일관된 상태가 되면서 트랜잭션이 종료된다.

실패 상태(failed)

  • 하드웨어, 소프트웨어의 문제나, 트랜잭션 내부의 오류 등의 이유로 장애가 발생하여 트랜잭션 수행이 중단된 상태이다.

철회 상태(aborted)

  • 트랜잭션의 수행이 실패하여 rollback 연산을 실행한 상태를 철회 상태라고 한다.
  • 지금까지 실행한 트랜잭션의 연산을 모두 취소하고 트랜잭션이 수행되기 전의 데이터베이스 상태로 되돌리면서 트랜잭션이 종료된다.

주의

  • 꼭 필요한 최소의 코드에만 적용
  • 일반적으로 DB 커넥션은 개수가 제한적이고 각 단위 프로그램이 커넥션을 소유하는 시간이 길어진다면 사용 가능한 여유 커넥션의 개수는 줄어들게 된다.

참고 자료 : 쉬운코드 https://www.youtube.com/watch?v=sLJ8ypeHGlM&list=PLcXyemr8ZeoREWGhhZi5FZs6cvymjIBVe&index=7

0개의 댓글