트랜잭션이란, 데이터베이스의 DML, 즉 삽입, 갱신, 삭제와 관련된 논리적인 작업을 말한다.
트랜잭션은 ACID 라는 특징을 가지고 있다.
트랜잭션의 처리가 완전히 끝나지 않았을 경우에는, 전혀 이루어지지 않은 것과 같아야 한다. ( All or Nothing )
트랜잭션의 실행이 성공적으로 완료되면, 데이터베이스는 모순 없이 일관성이 보존된 상태여야 한다.
어떤 트랜잭션도 다른 트랜잭션의 부분적 실행 결과를 볼 수 없다.
트랜잭션을 점유하고 있는 동안에는 Lock 을 걸어서, 다른 트랜잭션이 접근하지 못하도록 해야 한다.
트랜잭션이 성공하면, 트랜잭션의 결과를 영구적으로 보장해야 한다.
실행 ( Active ) : 트랜잭션이 실행 중인 상태
부분 완료 ( Partially Committed ) : 트랜잭션이 마지막 연산까지 실행했지만, Commit 연산이 실행되기 직전의 상태
완료 ( Committed ) : 트랜잭션이 성공적으로 종료된 상태
실패 ( Failed ) : 트랜잭션 실행에 오류가 발생하여 중단된 상태
철회 ( Aborted ) : 트랜잭션이 비정상적으로 종료되어 Rollback 연산을 수행한 상태
동시성 제어는, 동시에 실행되는 여러 개의 트랜잭션이 작업을 성공적으로 마칠 수 있도록 지원합니다.
락킹 ( Locking ) : 트랜잭션이 데이터를 접근하는 동안, 다른 트랜잭션이 접근하지 못하도록 Lock 을 걸어서 제어하는 방법
타임스탬프 ( Timestamping ) : 트랜잭션마다 고유한 타임스탬프를 부여하여, 트랜잭션의 실행 순서를 결정하는 방법
적합성 ( Validation ) : 먼저 트랜잭션을 수행하고, 트랜잭션을 종료할 때, 적합성을 검증하여, 트랜잭션을 종료할지, Rollback 할지 결정하는 방법
데이터베이스 시스템은 트랜잭션 직렬화 ( Serializability ) 를 보장하는, 동시성 제어를 통해 트랜잭션을 정상적으로 수행합니다.
동시성 제어 실패로 인한 대표적인 오류 현상에는, 갱신 손실, 불일치 현상, 연쇄 복귀 등이 있습니다.
두 개의 트랜잭션이 같은 데이터를 갱신할 때, 마지막에 갱신한 트랜잭션이 수행한 갱신 결과만 반영되고, 처음에 갱신한 트랜잭션이 수행한 갱신 결과는 손실되는 현상을 말합니다.
두 개의 트랜잭션이 같은 데이터를 조회할 때, 첫 번째 트랜잭션이 조회한 데이터와 두 번째 트랜잭션이 조회한 데이터가 일치하지 않는 현상을 말합니다.
트랜잭션 T1 이 트랜잭션 T2 에 의해 갱신된 데이터를 읽고, 트랜잭션 T1 이 Rollback 되면, 트랜잭션 T2 도 Rollback 되는 현상을 말합니다.
갱신 손실 문제를 해결하려면, 상대방 트랜잭션이 데이터를 사용하는지를 알 수 있는 규칙이 필요하다. 즉, 자신이 데이터를 수정중이라는 사실을 알리면 된다.
알리는 방법으로 락 ( Lock ) 이라는, 잠금장치를 사용한다.
공유 락 ( Shared Lock ) : 데이터를 읽을 때 사용하는 락
배타 락 ( Exclusive Lock ) : 데이터를 갱신할 때 사용하는 락
트랜잭션은 락을 두 단계에 걸쳐서 사용한다.
확장 단계 ( Growing Phase, expanding phase ) : 트랜잭션은 필요한 락을 획득하는 단계로, 이 단계에서는 이미 획득한 락을 해제하지 않는다.
축소 단계 ( Shrinking Phase ) : 트랜잭션이 락을 해제하는 단계로, 이 단계에서는 새로운 락을 획득하지 않는다.
2단계 락킹 기법을 사용하면, 데이터의 일관성을 유지할 수 있다. 하지만, 두 개 이상의 트랜잭션이 각각 자신의 데이터에 대하여 락을 획득하고, 상대방 데이터에 대하여, 락을 요청하면, 무한 대기 상태에 빠질 수 있다. 이러한 현상을 데드락 ( Deadlock ) 혹은 교착상태라고 한다.
데드락을 처리하는 방법에는, 타임아웃 ( Timeout ) 과 롤백 ( Rollback ) 이 있다.
타임아웃 ( Timeout ) : 트랜잭션이 일정 시간동안 락을 획득하지 못하면, 트랜잭션을 강제 종료시키는 방법
롤백 ( Rollback ) : 중지된 트랜잭션에서 변경한 데이터를 원래 상태로 되돌리는 방법
데드락은 대기 그래프 ( Wait-for-graph ) 를 통해 발견할 수 있다.
앞서 설명한 락은, 트랜잭션의 동시성을 제어하는 방법이다.
하지만, 락을 사용하면, 트랜잭션의 동시성은 제어할 수 있지만, 트랜잭션의 동시성이 높아질수록, 락 경합이 심해져서, 트랜잭션의 처리 성능이 떨어지게 된다.
이러한 문제를 해결하기 위해, 트랜잭션 격리 수준 ( Transaction Isolation Level ) 을 사용한다.
MySQL InnoDB의 기본 트랜잭션 고립 수준은 REPEATABLE READ 이다.
InnoDB는 이 고립 수준을 사용하여 트랜잭션 중 발생할 수 있는 일관성 없는 읽기 문제를 최소화한다.
1
2
3
4
5
6
7
| 모드 | READ UNCOMMITTED |
|------------|-----------------------------------------------------------|
| LOCK | SELECT 문 - 공유락 X |
| | UPDATE 문 - 배타락 O |
| | 다른 트랜잭션의 공유락과 베타락이 걸린 테이블을 읽음 |
| SQL 문 | SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED |
| 문제점 | 오손 읽기, 반복불가능 읽기, 유령데이터 읽기 |
1
2
3
4
5
6
7
8
| 모드 | READ COMMITTED |
|------------|-----------------------------------------------------------|
| LOCK | SELECT 문 - 공유락 X |
| | UPDATE 문 - 배타락 O |
| | 다른 트랜잭션의 공유락은 읽지만, 배타락은 읽지 못함 |
| SQL 문 | SET TRANSACTION ISOLATION LEVEL READ COMMITTED |
| 문제점 | 반복불가능 읽기, 유령데이터 읽기 |
1
2
3
4
5
6
7
| 모드 | REPEATABLE READ |
|------------|-----------------------------------------------------------|
| LOCK | SELECT 문 - 공유락을 걸고 트랜잭션 끝까지 유지 |
| | UPDATE 문 - 배타락 O |
| | 다른 트랜잭션의 공유락은 읽지만, 배타락은 읽지 못함 |
| SQL 문 | SET TRANSACTION ISOLATION LEVEL REPEATABLE READ |
| 문제점 | 유령데이터 읽기 |
1
2
3
4
5
6
7
8
| 모드 | SERIALIZABLE |
|------------|-----------------------------------------------------------|
| LOCK | SELECT 문 - 공유락을 걸고 끝나면, 바로 해지 |
| | UPDATE 문 - 배타락 O |
| | 다른 트랜잭션의 공유락은 읽지만, 배타락은 읽지 못함 |
| | 인덱스에 공유락을 설정하여, 다른 트랜잭션의 INSERT 를 막음 |
| SQL 문 | SET TRANSACTION ISOLATION LEVEL SERIALIZABLE |
| 문제점 | 없음 |
1
2
3
4
5
6
| | 오손 읽기 | 반복불가능 읽기 | 유령데이터 읽기 |
|---|:---:|:---:|:---:|
| READ UNCOMMITTED | 예 | 예 | 예 |
| READ COMMITTED | 아니오 | 예 | 예 |
| REPEATABLE READ | 아니오 | 아니오 | 예 |
| SERIALIZABLE | 아니오 | 아니오 | 아니오 |
오손 읽기 ( Dirty Read ) : 다른 트랜잭션이 COMMIT 하지 않은 데이터를 읽은 후, 다른 트랜잭션이 철회 (ROLLBACK) 하면서, 읽은 데이터가 취소되는 현상
반복불가능 읽기 ( Non-Repeatable Read ) : 트랜잭션이 같은 데이터를 다시 읽을 때, 다른 트랜잭션이 해당 데이터를 갱신하여, 다른 값을 읽는 현상
유령데이터 읽기 ( Phantom Read ) : 트랜잭션이 같은 데이터를 다시 읽을 때, 다른 트랜잭션이 해당 데이터를 삽입하여, 데이터가 존재하는 것처럼 읽는 현상
회복 ( Recovery ) 은, 트랜잭션의 성공적인 종료를 보장하기 위해, 트랜잭션이 비정상적으로 종료되었을 때, 데이터베이스를 일관된 상태로 되돌리는 작업을 말한다.
Undo 기법 : 트랜잭션이 비정상적으로 종료되면, 트랜잭션이 갱신한 데이터를 이전 값으로 복원하는 방법
Redo 기법 : 트랜잭션이 비정상적으로 종료되면, 트랜잭션이 갱신한 데이터를 다시 적용하는 방법
즉시 갱신 ( Immediate Update ) : 트랜잭션이 갱신한 데이터를 바로 데이터베이스에 반영하는 방법
지연 갱신 ( Deferred Update ) : 트랜잭션이 갱신한 데이터를 트랜잭션이 커밋될 때까지 임시 영역에 보관하고, 트랜잭션이 커밋되면, 임시 영역에 보관된 데이터를 데이터베이스에 반영하는 방법
데이터베이스와 트랜잭션 로그 파일을 동기화한 후, 동기화한 시점을 로그 파일에 기록해 두는데 이를 체크포인트라고 한다.
데이터베이스와 클라이언트(사용자 또는 애플리케이션) 간의 상호작용 기간을 말한다. 이 세션은 클라이언트가 데이터베이스에 연결을 시작할 때 생성되고, 연결을 종료할 때 종료된다. DB 세션 동안에는 여러 데이터베이스 작업들이 수행될 수 있으며, 이러한 작업들은 세션의 컨텍스트 안에서 관리된다.
Commit, Rollback, 그리고 Auto Commit 설정은 데이터베이스 트랜잭션 관리의 핵심 개념들이다. 이들은 데이터베이스에서 데이터의 일관성과 무결성을 유지하는 데 중요한 역할을 한다.
데이터베이스 트랜잭션이 성공적으로 완료되었음을 나타내며, 트랜잭션 동안 수행된 모든 변경사항을 데이터베이스에 영구적으로 반영한다.
트랜잭션 동안 발생한 모든 변경사항을 취소하고, 데이터베이스를 트랜잭션 시작 시점의 상태로 되돌린다.
데이터베이스 시스템이 각각의 데이터베이스 명령문(예: SQL 쿼리)이 실행된 직후 자동으로 commit을 수행하는 것을 말한다.
일반적으로 데이터베이스 시스템은 Auto Commit 모드가 기본적으로 설정되어있다.
이 모드에서는 사용자가 명시적으로 commit이나 rollback을 호출하지 않아도 각 SQL 명령문이 개별적인 트랜잭션으로 실행되며, SQL 명령문이 성공적으로 완료되면 commit이 자동으로 수행된다.