Database Transaction

김법우·2022년 7월 5일
0

Nest.js

목록 보기
4/10
post-thumbnail

Database Transaction

Transaction 이란?

정의

트랜잭션은 데이터베이스의 상태를 변화시키는 하나의 논리적 기능을 수행하기 위한 작업의 단위, 한번에 수행되어야 할 일련의 연산들의 묶음을 의미한다.

언제나 용어의 정의는 하나하나 뜯어보며 이해하면 쉬워진다. 데이터베이스의 상태를 변화시킨다는 것은 무엇일까?

우리가 일반적으로 사용하는 SQL 쿼리문을 떠올려보면, 우리는 어떠한 목적을 가지고 SQL 쿼리문을 사용해 데이터베이스에 저장된 튜플들(데이터)에 접근하고 조작한다. 특정 회원의 잔여 포인트 차감, 고객 잔고에서 10만원 차감 등등의 목적을 가지고 데이터를 조작하는 것이다.

특정 회원의 잔여 포인트에서 5포인트를 차감하는 것은 해당 튜플의 잔여 포인트에서 5포인트를 뺸 값을 저장하는 것과 같다. 고객 잔고에서 10만원을 차감하는 것도 마찬가지이다. 이처럼 상태변경은 데이터베이스에 저장된 데이터를 변경하는 것을 말한다.

그렇다면 상태를 변화시키는 하나의 논리적 기능, 작업의 단위는 무엇을 의미할까?

위의 두 예시는 각각의 작업이 목적을 이루기 위해 1번의 상태 변경만을 요구한다. 반면 단순히 예치금 차감이 아닌 계좌이체를 구현해야 하는 상황을 떠올려보자. 계좌이체를 구현하기 위해 고객 A 잔고에서 10만원을 차감하고 고객 B 잔고에 10만원을 더해야 할 것이다.

여기에서 우리가 원하는 논리적 작업은 계좌 이체이다. 이것을 구현하기 위해서는 2개의 튜플에 대해 상태를 변경해야한다. 따라서 계좌 이체가 논리적 작업이 되고, A 에서 10만원을 차감한 뒤 B 에 10만원을 추가하는 2개의 쿼리문을 합친 것이 작업의 단위이다.

따라서 정리하면, 트랜잭션이란 쪼갤 수 없어 한번에 수행되어야 하는 데이터베이스의 처리 작업 묶음이다.

목적

그런데 왜 굳이 트랜잭션이라는 개념 자체를 이해해야 하는 걸까? 위에서 언급한 작업들은 논리적인 작업의 개념을 빼고 본다면 A 에서 차감하는 작업 1개와 B 에서 추가하는 작업 1개, 총 2개의 작업으로 나눌 수 있다.

하지만 문제는 논리적으로는 하나여야 하는 작업이 위 처럼 나누어짐으로서 발생한다. 만약 A 에게서 돈을 차감하기 위해 Update 문을 실행했다고 생각해보자. A 에게 100 만원이 저장되어 있엇는데 10 만원이 차감되어 90 만원이 되었다. 이후에 B 가 가진 100만원에 10 만원을 더할려고 하는 와중, 알 수 없는 오류로 인해 수정하는 연산이 실패했다면? 이러한 현상은 심각한 오류를 야기한다. A 에게서 10 만원이 꺼내졌는데 돈을 받은 사람은 아무도 없다.

우리가 원하는 이상적인 계좌이체는 위와 같은 상황에서는 모든 상황이 이전으로 되돌아가 A 에게 계좌 이체가 실패했음을 알리고 다시 잔고를 100만원으로 복구해주는 것이다.

이것이 트랜잭션의 목적이다. 논리적으로 하나처럼 처리되었으면 하는 데이터베이스 상태 변경 연산들을 하나 처럼 처리하는 단위를 만드는 것.

트랜잭션에 대해 공부를 하며 이것 저것 찾아보다보니 내가하는 로스트아크에서도 이런 저런 부분들이 트랜잭션 처리가 되어 있겟지 하는 생각을 많이 한다. 무기 강화 버튼을 누름과 동시에 인벤토리에서 일주일동안 모은 재료 아이템들이 빠져나갔지만 무기 강화 레벨이 그대로라면? 상상만해도 끔찍하다.

하나처럼 처리된다라는 개념은 아래에서 ACID 를 통해 자세히 알아보자!

조금 더 자세히, Transaction

ACID?!

트랜잭션이 하나의 논리적 작업 단위로서 처리되기 위해서는 다음과 같은 특징, 성질을 만족해야 한다.

  • Atomicity 원자성 원자성은 트랜잭션이 데이터베이스에 모두 반영되거나 전혀 반영되지 않아야 한다. 즉, 하나의 논리 작업 단위에 포함된 일련의 상태 변경 연산들을 모두 정상 수행하거나, 아무것도 수행하지 않아야 한다.
  • Consistency 일관성 트랜잭션의 처리가 완료되면 일관성 있는 데이터베이스 상태로 변환해야 한다. 즉, 시스템이 가지고 있는 고정요소가 트랜잭션 전 후로 상태가 같아야 한다. 여기서 고정요소란 시스템의 자체적인 특징을 의미한다. “만약 모든 계좌의 잔고는 0보다 크거나 같다”가 위 예시의 무결성 제약이라면, 트랜잭션의 수행 결과 또한 무결정 제약을 따라야하고 만족하지 않을 경우 트랜잭션을 중단해야 한다.
  • Isolation 고립성 트랜잭션을 수행하는 중 다른 트랜잭션의 연산 작업이 끼어들지 못하도록 보장하는 것. 특정 트랜잭션 밖에 있는 다른 연산들이 트랜잭션 중간중간 나타나는 상태에 대해 전혀 모르도록 하는 것을 의미한다. 위에서 A 에서 10만원을 차감하는 연산을 완료한 시점에서 A 의 잔고는 90 만원이지만, 이 90 만원이 남아있다는 상태를 트랜잭션 밖에서는 볼 수 없다는 것.
  • Durability 영속성 트랜잭션의 처리가 완료되면 트랜잭션의 결과가 데이터베이스에 영구적으로 반영되야 한다.

각 앞글자를 따서 ACID 라고 하는데, 4가지의 성질을 만족한다면 강화 재료만 빠져나가서 화나는 일 없이 로스트아크를 즐길 수 있다.

Commit 과 Rollback

위에서 말한 여러개의 상태 변경 연산을 하나의 논리적 작업으로 처리하기하는 원리를 알기 위해서는 2가지 개념을 이해해야 한다. 바로 Commit 과 RollBack 이다.


출처 : https://devuna.tistory.com/30

Commit 은 모든 상태 변경 연산들이 정상적으로 완료되면, 이 사항을 한번에 DB에 반영하는 것이고 Roll Back 은 부분적으로 연산이 실패 할 경우 트랜잭션 실행 전으로 상태를 되돌리는 것을 의미한다.

트랜잭션은 위의 그림처럼 Acitvate (트랜잭션이 정상적으로 실행 중인 상태) 단계에서 시작해서 작업 성공 여부에 따라 Partially Commited 단계 (마지막 연산까지 모두 실행했지만 Commit 연산은 실행하기 전 단계) 혹은 Failed (연산 수행간 오류 발생한 상태) 단계로 진행된다.

Partially Commited 단계에서 Commit 연산을 수행하게 되면 이는 데이터베이스에 트랜잭션 결과를 영구적으로 반영하고 종료한다.

Failed 단계에서 Roll Back 연산을 수행하게 되면 데이터베이스에 트랜잭션 과정에서 발생한 모든 연산을 되돌리고 종료한다.

참고 자료

[DB기초] 트랜잭션이란 무엇인가?

[DB]트랜잭션(Transaction)이란?/트랜잭션의 개념,특징, 연산과정/savepoint

데이터베이스 트랜잭션(Transaction)란?

ACID란?

다음 글에서는 …

내가 좋아하는 Nest.js 와 찰떡 궁합인 TypeORM 을 활용한 데이터베이스 트랜잭션을 구현해 본다. 공식 문서에서 추천한 2가지의 방법과, 기술 블로그를 보며 배운 1가지의 방법으로 트랜잭션을 구현해 볼 생각이다.

profile
개발을 사랑하는 개발자. 끝없이 꼬리를 물며 답하고 찾는 과정에서 공부하는 개발자 입니다. 잘못된 내용 혹은 더해주시고 싶은 이야기가 있다면 부디 가르침을 주세요!

0개의 댓글