트랜잭션이란 DB에서 처리되는 논리적인 연산 단위를 의미한다. 1개의 트랜잭션에는 1개 이상의 SQL문이 포함된다. 또한 트랜잭션은 분할할 수 없는 최소의 단위로, 전부 적용하거나 전부 취소하는 ALL OR NOTHING의 개념이다.
트랜잭션은 데이터베이스 서버에 여러 개의 클라이언트가 동시에 액세스 하거나 응용프로그램이 갱신을 처리하는 과정에서 중단될 수 있는 경우 등 데이터 부정합을 방지하고자 할 때 사용한다. 트랜잭션의 목적을 달성하며 각각의 트랜잭션을 안전하게 수행하기 위해선 ACID 조건을 충족해야 한다.
- 트랜잭션은 DB에 모두 반영되거나, 전혀 반영되지 않아야 한다.
- 트랜잭션이 실행을 성공적으로 완료하면 데이터베이스의 상태가 일관성을 유지해야한다.
- 트랜잭션 수행 시에는 다른 트랜잭션의 연산 작업이 끼어들지 않고 독립적으로 실행돼야 한다.
- 성공적으로 수행된 트랜잭션은 영원히 반영되어야 한다. 모든 트랜잭션은 로그로 남겨, 시스템 장애 발생 시 이전 상태로 되돌릴 수 있어야 한다.
같은 데이터에 여러명이 동시에 접근하려 하는 경쟁 상태(Race Condition)에서는 아래와 같은 문제들이 생길 수 있다.
Dirty read 커밋되지 않은 데이터 읽기
Dirty write 커밋되지 않은 데이터 덮어쓰기
read skew 읽는동안 데이터가 변경
Lost update 변경 유실
이런 상황에서 트랜잭션의 독립성을 지키려면 트랜잭션을 격리시켜줘야한다. 트랜잭션의 격리 수준은 대표적으로 네가지가 있다.
- 커밋되지 않은 데이터도 읽을 수 있다.
- 사실상 격리를 하지 않고 그냥 냅둔 것이다.
- 정합성에 문제가 많기 때문에 거의 쓰지 않는다.
- 커밋된 데이터만 읽을 수 있다.
- 대부분의 RDB에서 기본적으로 사용한다.
- 하지만 어떤 트랜잭션이 실행되는 중간에 누가 커밋을 하면
같은 데이터를 조회해도 다른 값이 조회되는 문제가 생긴다.(Non-Repeatable Read)
- 트랜잭션마다 트랜잭션ID를 부여해서, 나의 트랜잭션 ID보다 작은 번호에서 변경한 것만 읽게 한다.
- 하지만 어떤 트랜잭션이 실행되는 중간에 작은 번호에서 커밋을 하면 존재하지 않는 값을 읽을 수도 있는 문제가 생긴다.(Phantom Read)
- 하나의 트랜잭션이 끝난 다음에 다음 트랜잭션을 실행한다.
- 가장 단순하지만 동시 처리성능이 많이 떨어진다.
트랜잭션을 확실히 격리하여 구분할 수록 동시처리 성능은 떨어진다. 이 네가지의 단계중 하나를 선택해서 성능과 독립성을 적당히 조정해야한다.