본문으로 건너뛰기

1 Transaction

  • 하나의 논리적 작업 단위를 구성하는 일련의 연산들의 집합을 트랜잭션이라고 합니다.
  • 트랜잭션은 작업의 완전성을 보장해줍니다.
  • 즉, 논리적인 작업 셋을 모두 완벽하게 처리하거나 또는 처리하지 못할 경우에는 원 상태로 복구해서 작업의 일부만 적용되는 현상(Partial Update)이 발생하지 않게 만들어주는 기능입니다.

1.1 Transaction과 Locking

Locking

  • Locking과 서로 비슷한 개념이지만 Locking은 동시성을 제어하기 위한 기능입니다.
  • 반면 트랜잭션은 데이터의 정합성을 보장하기 위한 기능입니다.
  • Locking.md 참고

1.2 Transaction을 지원하는 스토리지 엔진의 장점

  • 많은 개발자들이 트랜잭션에 대해 깊이 생각하기 싫어서 트랜잭션을 지원하지 않는 MyISAM을 선택한다고 하는데 트랜잭션을 지원하지 않는 스토리지 엔진의 테이블이 더 많은 고민거리를 만들어냅니다.
  • 트랜잭션을 지원하는 InnoDB는 쿼리 중 일부라도 오류가 발생하면 트랜잭션 원칙대로 전체를 원상태로 만듭니다.
  • 하지만 트랜잭션을 지원하지 않는 MyISAM을 사용했는데 쿼리 중 일부가 오류가 난다면 부분 업데이트 현상이 발생하면서 실패한 쿼리로 인해 남은 레코드를 다시 삭제하는 재처리 작업을 직접 해야합니다.
  • 트랙잭션은 골치 아픈 기능이 아니라 그만큼 애플리케이션 개발에서 고민해야 할 문제를 줄여주는 아주 필수적인 DBMS의 기능이라는 점을 기억해야합니다.

2 ACID 원칙

  • 트랜잭션은 완전성 보장을 위해 ACID 원칙을 준수해야합니다.
  • ACID는 데이터베이스 트랜잭션이 안전하게 수행되도록 보장하는 4가지 속성을 말한다.
  • ACID는 Atomicity(원자성), Consistency(일관성), Isolation(고립성), Durability(지속성)의 약자이다.

2.1 Atomicity(원자성)

  • 트랜잭션은 종종 여러 명령문으로 구성됩니다.
  • 원자성은 각 트랜잭션이 완전히 성공하거나 완전히 실패하는 단일 "단위"로 처리되도록 보장합니다.
  • 트랜잭션의 모든 연산이 데이터베이스에 반영되던가 아니면 한개의 연산도 반영되지 말아야합니다.
    • 데이터베이스 업데이트가 부분적으로 발생하는 것을 방지합니다.
  • 원자성은 트랜잭션의 연산이 일부만 실행되고 실패하는 경우, 이전 상태로 롤백되어야 한다는 것을 의미합니다.

2.2 Consistency(일관성)

  • 데이터베이스의 제약사항이 트랜잭션을 시작하기 전과 후 같아야합니다.
  • 트랜잭션 수행이 보존해야 할 일관성은 기본 키, 외래 키 제약과 같은 명시적인 무결성 제약 조건들뿐만 아니라, 자금 이체 예에서 두 계좌 잔고의 합은 이체 전후가 같아야 한다는 사항과 같은 비명시적인 일관성 조건들도 있습니다.

2.3 Isolation(독립성/고립성)

  • 트랜잭션은 종종 동시에 실행된다
  • 독립성이란 각각의 트랜잭션이 동시에 실행되고 있는 다른 트랜잭션을 인지하지 못한다는 것을 의미합니다.
  • 트랜잭션의 중간 결과과 동시에 실행되고 있는 다른 트랜잭션으로부터 감쳐줘야합니다.
  • 트랜잭션 연산중에 다른 트랜잭션이 값을 읽어버리면 잘못 된 값을 읽을 수 있기 때문입니다.
  • Isolation 성질을 보장할 수 있는 가장 쉬운 방법은 모든 트랜잭션을 순차적으로 수행하는 것입니다.
  • 하지만 병렬적 수행의 장점을 얻기 위해서 DBMS는 병렬적으로 수행하면서도 일렬(serial) 수행과 같은 결과를 보장할 수 있는 방식을 제공하고 있습니다.

2.4 Durability(지속성)

  • 내구성은 트랜잭션이 커밋 된 후 시스템 오류(예 : 정전 또는 충돌)의 경우에도 커밋 된 상태로 유지되도록 보장합니다.
    • 중간에 시스템에 문제가 발생해도 데이터베이스 로그 등을 사용해서 성공한 트랜잭션 내용을 복구해야 합니다.
  • 일반적으로 완료된 트랜잭션이 비 휘발성 메모리에 기록된다는 것을 의미합니다.

3 Transaction을 사용할 때 주의할 점

  • 트랜잭션은 꼭 필요한 최소의 코드에만 적용하는 것이 좋습니다.
    • 즉 트랜잭션의 범위를 최소화하는 것이 좋습니다.
  • 일반적으로 데이터베이스 커넥션은 개수가 제한적입니다.
    • 그런데 각 단위 프로그램이 커넥션을 소유하는 시간이 길어진다면 사용 가능한 여유 커넥션의 개수는 줄어들게 됩니다.
    • 그러다 어느 순간에는 각 단위 프로그램에서 커넥션을 가져가기 위해 기다려야 하는 상황이 발생할 수 있습니다.

3.1 외부 통신 작업

  • 메일 전송이나 FTP 파일 전송 작업 또는 네트워크를 통해 원격 서버와 통신하는 등과 같은 작업은 어떻게 해서든 DBMS의 트랙잭션 내에서 제거하는 것이 좋습니다.
  • 외부 통신 작업은 트랜잭션의 범위를 늘리게 되어 트랜잭션의 동시성을 떨어뜨리게 됩니다.
  • 외부 통신 작업은 트랜잭션 외부에서 처리하는 것이 좋습니다.

3.2 외부 처리 작업

  • 트랜잭션 내에서 외부 처리 작업을 수행하는 것은 트랜잭션의 범위를 늘리게 되어 트랜잭션의 동시성을 떨어뜨리게 됩니다.
  • 따라서 이러한 작업들은 보상 트랜잭션(Compensating Transaction) 패턴을 사용하여 처리하는 것이 좋습니다.
  • 보상 트랜잭션이란 이미 완료된 트랜잭션의 효과를 취소하기 위해 실행되는 새로운 트랜잭션을 의미합니다.
    • 예를 들어, 결제 완료 후 재고 차감에 실패한 경우 → 결제 취소 트랜잭션 실행
    • 주문 완료 후 배송 처리에 실패한 경우 → 주문 취소 및 환불 트랜잭션 실행
    • 포인트 적립 후 알림 발송에 실패한 경우 → 포인트 차감 트랜잭션 실행

4 Transaction State

트랜잭션 상태 다이어그램

  • Active
    • 트랜잭션의 활동 상태. 트랜잭션이 실행중이며 동작중인 상태를 말한다.
  • Failed
    • 트랜잭션 실패 상태. 트랜잭션이 더이상 정상적으로 진행 할 수 없는 상태를 말한다.
  • Partially Committed
    • 트랜잭션의 Commit 명령이 도착한 상태. 트랜잭션의 commit이전 sql문이 수행되고 commit만 남은 상태를 말한다.
  • Committed
    • 트랜잭션 완료 상태. 트랜잭션이 정상적으로 완료된 상태를 말한다.
  • Aborted
    • 트랜잭션이 취소 상태. 트랜잭션이 취소되고 트랜잭션 실행 이전 데이터로 돌아간 상태를 말한다.
  • Partially Committed 와 Committed 의 차이점
    • Commit 요청이 들어오면 상태는 Partial Commited 상태가 된다.
    • 이후 Commit을 문제없이 수행할 수 있으면 Committed 상태로 전이되고, 만약 오류가 발생하면 Failed 상태가 된다.
    • 즉, Partial CommitedCommit 요청이 들어왔을때를 말하며, CommitedCommit을 정상적으로 완료한 상태를 말한다.

5 자동 Commit

  • 자동 커밋으로 설정하면 각각의 쿼리 실행 직후에 자동으로 커밋을 호출합니다.
    • 자동 커밋 모드는 쿼리가 하나인 트랜잭션을 사용하는 방식입니다.
  • 따라서 커밋이나 롤백을 직접 호출하지 않아도 되는 편리함이 있습니다.
    • 하지만 쿼리를 하나하나 실행할 때 마다 자동으로 커밋이 되어버리기 때문에 우리가 원하는 트랜잭션 기능을 제대로 사용할 수 없습니다.
  • 일반적으로 자동 커밋이 설정되어 있기 때문에 이를 수동 커밋 모드로 변경해야합니다.
    • 이렇게 수동 커밋 모드로 변경하는 행위를 트랜잭션을 시작한다라고 합니다.
      • 수동 커밋을 설정한 이후에는 commit 또는 rollback을 호출해야 합니다.
    • 만약 호출하지 않으면 timeout이 발생하여 자동으로 롤백됩니다.

5.1 예시

set autocommit false;
update member set money=10000 - 2000 where member_id = 'memberA';
update member set money=10000 + 2000 where member_id = 'memberB';
commit;
  • MySQL에서는 autocommit을 사용하여 자동 커밋 모드를 설정할 수 있습니다.
  • autocommitfalse로 설정하면 자동 커밋 모드가 해제되어 수동 커밋 모드로 변경됩니다. 이를 통해 트랜잭션을 시작할 수 있습니다.
  • 위의 예시는 memberA의 돈을 2000원 차감하고, memberB의 돈을 2000원 추가하는 쿼리입니다.
  • commit을 호출하여 트랜잭션을 완료합니다.

관련 자료