[Database] - 데이터베이스의 트랜잭션과 PostgreSQL
- 이번 포스팅에서는 데이터베이스에서 사용되는 트랜잭션의 개념과 성질에 대해 살펴보고, PostgreSQL을 예시로 실제 SQL에서 트랜잭션이 어떻게 동작하고 있는지 살펴봅니다.
트랜잭션의 개념
일반적으로 대부분의 데이터베이스에서는 하나의 논리적 작업 단위 또는 일련의 연산으로서 트랜잭션(Transaction) 단위를 이용합니다. 이는 프로그램의 실행 단위로서, 다양한 데이터에 대한 접근 및 업데이트를 수행하는 단위이기도 합니다.
ACID 성질
데이터베이스는 각각의 트랜잭션에 대해서 데이터의 무결성(integrity)을 보장하기 위해 아래의 네 가지 성질을 보장합니다. 이 성질들을 영어의 알파벳 첫 글자를 따서 ACID 성질이라고 합니다.
- 원자성(Atomicity) : 해당 단위의 작업이 모두 실행되거나, 그렇지 않으면 모두 실행되지 않은 상태임을 보장해야 합니다. 즉, all or nothing이 보장되어야 합니다.
- 일관성(Consistency) : 트랜잭션의 실행은 데이터베이스의 일관성을 유지해야 합니다.
- 독립성(Isolation) : 비록 수많은 트랜잭션들이 동시에 실행되더라도, 각각의 트랜잭션은 서로의 실행에 대해서 전혀 모르는 상태로 수행이 되어야 합니다. 즉, 아직 수행 중인 다른 트랜잭션들의 작업 내역은 해당 트랜잭션에는 영향을 미쳐서는 안됩니다.
- 영속성(Durability) : 트랜잭션이 성공적으로 수행되었다면, 해당 작업 내역은 데이터베이스에 영구적으로 반영되어야 합니다.
트랜잭션의 상태
일반적으로 트랜잭션의 상태는 다음과 같이 분류합니다.
- 활성화(Active) : 트랜잭션이 실행된 초기의 상태를 의미합니다.
- 부분 커밋(Partially Committed) : 트랜잭션의 일부 작업이 수행된 뒤, 완전히 커밋되기 전의 상태입니다. 이 상태에서는 트랜잭션이 실패할 수 있습니다.
- 실패(Failed) : 트랜잭션의 작업이 더 이상 정상적으로 실행될 수 없는 상태입니다.
- 중단(Aborted) : 트랜잭션이 롤백(roll back)된 뒤의 상태입니다. 여기서의 롤백이란 트랜잭션이 실행 전의 상황으로 돌려 놓는 것을 의미합니다. abort가 된 이후 트랜잭션은 내부적으로 논리적 오류가 없다면 재실행되거나 죽게됩니다.
- 커밋(Committed) : 트랜잭션이 모든 작업을 성공적으로 수행한 상태로, 해당 내역을 데이터베이스에 반영한 상태입니다.
각 상태들은 아래의 그림과 같이 서로 이동하게 됩니다.

PostgreSQL에서의 트랜잭션
그렇다면 우리가 흔히 데이터베이스에 접근하기 위해서 사용하는 SQL에서는 트랜잭션을 어떻게 관리하고 있을까요? 여기서는 PostgreSQL을 활용하여 확인해보도록 하겠습니다.

다음과 같이 Autocommit 모드를 확인하면 on이 되어있는 것을 확인할 수 있습니다. 즉, default 값으로 사용자의 요청에 대해서 암묵적으로 commit을 수행하고 있는 모습을 확인할 수 있습니다. 이와 같이 auto commit이 설정되어 있는 상태에서는 사용자가 추가적인 요청을 하지 않아도 아래와 같이 각 요청들을 데이터베이스에 반영하고 있는 모습을 확인할 수 있습니다.



만약, auto commit 설정을 off로 바꾼다면 어떻게 되는지 확인해보도록 하겠습니다.

auto commit을 off로 설정한 뒤, 아래와 같이 Create Table 명령어를 실행하니 shell의 모습이 postgres=# 에서 postgres=*#으로 바뀐 모습을 확인할 수 있습니다. 이는 트랜잭션이 실행 중에 있음을 나타내는 표시입니다. 즉, auto commit을 껐기 때문에 사용자가 요청한 한 문장을 자동으로 커밋하는 것이 아닌, 사용자가 직접 Commit 명령어를 실행할 때까지 하나의 트랜잭션으로 실행하는 것을 확인할 수 있습니다.

이런 상태에서, 새로운 사용자를 가정하고 psql shell을 하나 더 띄운 뒤, student2 테이블이 만들어졌는지 확인해보겠습니다.

아직 이전 트랜잭션이 commit 되지 않은 상태이기 때문에, 다른 트랜잭션이 해당 작업 내역(student2 테이블 생성)을 확인하려고 하자 확인할 수 없는 것을 볼 수 있습니다. 다시 이전 트랜잭션으로 돌아와 COMMIT 명령어를 실행해보겠습니다. shell 창의 프롬프트 모습이 바뀐 것을 확인할 수 있습니다.

그런 다음 앞서 켜뒀던 새로운 트랜잭션에서 앞서와 동일하게 student2 테이블을 조회해보도록 하겠습니다.

이미 이전 트랜잭션이 commit된 상태이기 때문에, 해당 트랜잭션의 작업 내역을 다른 트랜잭션에서도 확인할 수 있는 것을 볼 수 있습니다.
- 정리해보자면, PostgreSQL에서는 기본적으로 AutoCommit 모드가 on으로 설정되어 있기 때문에, 사용자의 명령 각각을 자동으로 commit 하고 있습니다. 만약 사용자가 트랜잭션의 단위를 직접 설정하고 싶다면 auto commit 모드를 off로 설정한 뒤, 작업을 수행할 수 있습니다.
- 위에서 본 것처럼, auto commit 모드를 off로 설정한 뒤, 트랜잭션을 실행하기 위해서 begin과 같은 명령어를 작성하지 않았습니다. PostgreSQL에서는 사용자의 명령이 들어오면 자동으로 트랜잭션을 실행하고, 사용자의 Commit 명령이나 Rollback 명령이 있을 때까지 트랜잭션을 실행하게 됩니다.
트랜잭션과 Serializablility
앞서 데이터베이스는 트랜잭션에 대해서 ACID 성질을 보장한다고 했는데요, 그러나 동시에 CPU를 효율적으로 활용하기 위해서는 수많은 트랜잭션을 동시에 처리해야 합니다. 다음 포스팅에서는 이렇듯 수많은 트랜잭션이 동시에 실행되는 와중에 어떠한 방식으로 트랜잭션의 성질을 유지하는지에 대해서 Serializablility 개념을 통해 살펴보도록 하겠습니다.
Reference