Aug, 2023
01. 트랜잭션
1. 트랜잭션의 개념
- 트랜잭션(transaction)
- DBMS에서 데이터를 다루는 논리적인 작업의 단위( = DBMS가 데이터베이스를 다룰 때 사용하는 작업(프로그램) 단위)
- 보통 단일 SQL 문을 사용하여 다루기도 하지만 여러 개의 SQL문을 순차적으로 수행하여 다루기도 한다
- 트랜잭션을 정의하는 이유
- 데이터베이스에서 데이터를 다룰 때 장애가 일어나면, 트랜잭션이 장애 발생 시 데이터 복구 작업의 단위로 쓰인다
- 데이터베이스에서 여러 작업이 동시에 같은 데이터를 다루면, 트랜잭션이 이 작업을 서로 분리하는 단위가 된다
- 트랜잭션은 전체가 수행되거나 또는 전혀 수행되지 않아야 한다(all or nothing)
BEGIN
1) A 계좌에서 10,000원을 인출하는 SQL UPDATE 문
2) B 계좌에 10,000원을 입금하는 SQL UPDATE 문
END
# 1)과 2)는 모두 수행되거나 아예 수행되지 않아야 한다
- START TRANSACTION 문과 COMMIT 문: 하나의 논리적인 작업의 단위로 만들어준다
- COMMIT: 트랜잭션의 종료를 알리는 SQL 문
START TRANSACTION
1) A 계좌에서 10,000원을 인출하는 SQL UPDATE 문
2) B 계좌에 10,000원을 입금하는 SQL UPDATE 문
COMMIT
# 1)과 2)는 모두 수행되거나 모두 수행되지 않는다!
- 트랜잭션이 데이터베이스에서 실행될 때 일어나는 상황
# 테이블: Customer(name, balance)
START TRANSACTION
# 1) 박지성 계좌를 읽어온다
# 2) 김연아 계좌를 읽어온다
# 잔고 확인
# 3) 예금인출 박지성
UPDATE Customer
SET balance = balance - 10000
WHERE name = '박지성';
# 4) 예금입금 김연아
UPDATE Customer
SET balance = balance + 10000
WHERE name = '김연아';
COMMIT /* 부분 완료 */
# 5) 박지성 계좌를 기록한다
# 6) 김연아 계좌를 기록한다
- 트랜잭션은 데이터베이스에 저장된 테이블을 읽어와 주기억장치 버퍼에 저장하고, 버퍼에 저장된 데이터를 수정한 후 최종적으로 데이터베이스에 다시 저장한다
- 세부 과정
- A 계좌(박지성)의 값을 하드디스크(데이터베이스)에서 주기억장치 버퍼로 읽어온다
- B 계좌(김연아)의 값을 하드디스크(데이터베이스)에서 주기억장치 버퍼로 읽어온다
- A 계좌(박지성)에서 10,000원을 인출한 값을 저장한다
- B 계좌(김연아)에서 10,000원을 입금한 값을 저장한다
- A 계좌(박지성)의 값을 주기억장치 버퍼에서 하드디스크(데이터베이스)에 기록한다
- B 계좌(김연아)의 값을 주기억장치 버퍼에서 하드디스크(데이터베이스)에 기록한다
- 트랜잭션의 사실적인 종료는 1~6이 완전히 끝난 후지만, DBMS는 1~4까지만 수행하고 사용자에게 완료 사실을 알리고 나머지 5, 6은 DBMS가 책임지고 수행한다(1 → 2 → 3 → 4 → COMMIT → 5 → 6 → 완료)→ 이유 2: 5, 6의 과정은 시간이 많이 소요되고, 다른 트랜잭션이 또 Customer 테이블을 필요로 할 수도 있기 때문이다
- ⇒ 트랜잭션은 임시로 종료를 선언하고 실제 데이터베이스에 기록하는 것은 DBMS가 수행한다!
- → 이유 1: DBMS가 동시에 많은 트랜잭션을 수행할 때, 각각의 트랜잭션이 하드디스크에 개별 접근하는 것을 피하고 DBMS가 일괄적으로 하드디스크에 접근하여 처리함으로써 사용자에게 빠른 응답성을 보장할 수 있다
- 트랜잭션의 수행 과정: 시작(begin) → 수행(1, 2, 3, 4) → 부분완료 → 버퍼내용 기록(5, 6) → 완료(commit)
- 부분완료: 트랜잭션의 종료를 사용자나 다른 트랜잭션에게 알리는 단계로, 부분완료된 트랜잭션은 DBMS가 다른 트랜잭션의 작업 처리 상황을 봐가면서 변경 내용을 하드디스크에 기록한다
2. 트랜잭션의 성질
- 트랜잭션과 프로그램의 차이점
구분 | 트랜잭션 | 프로그램 |
프로그램 구조 | START TRANSACTION ~ COMMIT | main() { ~ } |
다루는 데이터 | 데이터베이스에 저장된 데이터 | 파일에 저장된 데이터 |
번역기 | DBMS | 컴파일러 |
성질 | 원자성, 일관성, 고립성, 지속성 | - |
- 트랜잭션의 네 가지 성질: ACID 성질
- Atomicity(원자성)
- Consistency(일관성)
- Isolation(고립성)
- Durability(지속성)
1) Atomicity(원자성): 트랜잭션에 포함된 작업은 전부 수행되거나 아니면 전부 수행되지 않아야 한다(all or nothing)
- 트랜잭션이 원자처럼 더 이상 쪼개지지 않는 하나의 프로그램 단위로 동작해야 한다는 의미 → 일부만 수행되는 일이 없도록 전부 수행하거나 아예 수행을 하지 않아야 한다
- SQL에서는 트랜잭션의 시작과 끝을 표시하기 위해 START TRANSACTION ~ COMMIT 문을 사용한다
- 트랜잭션 중간에 작업이 잘못되면 회복(recovery) 알고리즘을 이용하여 변경한 내용을 취소한다(자의적으로 트랜잭션을 취소하는 명령어 ROLLBACK을 사용하기도 한다)
** 트랜잭션 제어 명령어(TCL, Transaction Control Language)
표준 명령어 문법 설명
표준 명령어 | 문법 | 설명 |
START TRANSACTION | SET TRANSACTION | 트랜잭션의 시작 |
COMMIT | COMMIT | 트랜잭션의 종료 |
ROLLBACK | ROLLBACK{TO <savepoint>} | 트랜잭션을 전체 혹은 <savepoint>까지 무효화시킴 |
SAVE | SAVEPOINT<identifier> | <savepoint>를 만듦 |
** MySQL에서 트랜잭션의 시작과 끝
- 시작: 표준 명령어는 ‘START TRANSACTION’이고, ‘SET TRANSACTION NAME <이름>’ 혹은 데이터를 변경하는 SQL 문이 나오면 자동으로 트랜잭션이 시작된다
- 끝: COMMIT 또는 ROLLBACK 문 혹은 DDL 문을 만날 때 자동으로 종료된다
- SAVEPOINT(저장점): 트랜잭션의 길이가 길 때, 트랜잭션의 중간 지점에 수정내용을 반영하는 포인트를 만들고, 이를 SAVEPOINT라고 한다
- 트랜잭션이 잘못되어 처음부터 다시 실행해야 할 경우, 트랜잭션의 처음이 아니라 SAVEPOINT까지 되돌아가면 트랜잭션 전체가 ROLLBACK되는 것을 막을 수 있다
- SAVEPOINT는 트랜잭션 안에 여러 개 만들 수 있다
2) Consistency(일관성): 트랜잭션을 수행하기 전이나 수행한 후나 데이터베이스는 항상 일관된 상태를 유지해야 한다
- 일관성은 테이블이 생성될 때 CREATE 문과 ALTER 문의 무결성 제약조건을 통해 명시되고, 트랜잭션은 이 조건에 다라 일관성을 유지한다
- 다만 수행 중 일시적으로 일관성을 유지하지 못하는 상태가 있을 수 있다
- ex) 계좌이체 트랜잭션에서의 일관성 조건은 ‘A계좌 + B계좌 = 20만 원’이다. 그런데 A 계좌에서 만 원을 인출하여 B 계좌에 입금하기 전에는 총액이 일시적으로 19만 원으로 줄어드는 일관성 없는(inconsistent) 상태가 되지만, 트랜잭션이 종료된 후에는 다시 조건을 만족한다
3) Isolation(고립성): 수행 중인 트랜잭션에 다른 트랜잭션이 끼어들어 변경 중인 데이터 값을 훼손하는 일이 없어야 한다
- 데이터베이스는 공유가 목적이기 때문에 여러 트랜잭션이 동시에 수행되고, 이때 각 트랜잭션은 다른 트랜잭션의 방해를 받지 않고 독립적으로 작업을 수행한다. 여러 트랜잭션이 동시에 수행될 때 상호 간섭이나 데이터 충돌이 일어나지 않는 현상을 고립성이라고 한다
- 동시성 제어(concurrency control): 동시에 수행되는 트랜잭션이 같은 데이터를 가지고 충돌하지 않도록 제어하는 작업
- 고립성을 유지하기 위해서는 변경 중인 임시 데이터를 다른 트랜잭션이 읽거나 쓰려고 할 때 제어하는 작업이 필요하다
- 동시성 제어보다 완화된 방법으로, 트랜잭션 고립 수준(isolation level)에 따라 트랜잭션의 상호 간섭을 완화시키는 방법도 있다
4) Durability(지속성): 수행을 성공적으로 완료한 트랜잭션은 변경한 데이터를 영구히 저장해야 한다.
- 트랜잭션이 정상적으로 완료 혹은 부분완료한 데이터는 반드시 데이터베이스에 기록되어야 하는데, 이러한 성질을 지속성이라고 한다
- DBMS 복구 시스템은 트랜잭션이 작업한 내용을 수시로 로그(log) 데이터베이스에 기록하였다가 문제가 발생하면 로그 파일을 이용하여 복구 작업을 수행한다 → 시스템이 멈추어도 트랜잭션 수행으로 변경된 내용은 디스크에 기록된다
- 트랜잭션의 상태도
- 부분완료: 트랜잭션 수행은 완료되었지만 변경 내용이 데이터베이스에 기록되었는지 확실하지 않은 상태
- DBMS가 최종적으로 변경 내용을 데이터베이스에 기록해야 완료(commited) 상태가 된다
- 시스템 내부의 문제 혹은 시스템 다운 등으로 DBMS가 변경 내용을 데이터베이스에 기록하지 못하면 실패(failed) 상태가 된다
- 실패: 트랜잭션을 중간에 중단하였거나 부분완료 상태에서 변경 내용을 데이터베이스에 저장하지 못한 상태
- 실패 상태에서는 DBMS는 트랜잭션이 수행한 작업을 모두 원상복구시킨다
3. 트랜잭션과 DBMS
DBMS는 트랜잭션이 ACID 성질을 유지할 수 있도록 지원한다
- 원자성을 유지하기 위해 회복(복구) 관리자 프로그램을 작동시킨다
- 회복 관리자 프로그램은 데이터베이스가 변경한 내용을 로그에 기록하고 있다가 트랜잭션에 문제가 생겼을 때 원래 상태로 되돌린다
- 일관성을 유지하기 위해 무결성 제약조건을 활용한다
- 트랜잭션 수행 시 데이터에 변경이 가해지면 미리 정의해둔 무결성 제약조건을 검사하여 일관성이 깨지는 것을 막는다
- 두 개의 트랜잭션이 동시에 수행될 때 트랜잭션 간에 간섭으로 일관성이 깨지는 현상은 무결성 제약조건을 검사하는 것으로 해결할 수 없고, 동시성 제어 알고리즘을 작동시켜야 한다
- 고립성을 유지하기 위해 동시성 제어 알고리즘을 작동시킨다
- 두 개의 트랜잭션이 동시에 수행될 때 간섭에 의해 데이터 값이 손상되면 고립성이 깨지고, 이 경우 동시성 제어 알고리즘을 작동시켜 여러 트랜잭션이 동시에 같은 데이터를 접근할 때 한 트랜잭션씩 순서대로 접근하는 것처럼 제어한다
- 지속성을 유지하기 위해 회복 관리자 프로그램을 이용한다
- 회복 관리자 프로그램은 데이터베이스가 변경한 내용을 로그로 기록하고 있다가 트랜잭션에 문제가 있을 때 원래 상태로 되돌린다
02. 동시성 제어
- 한 개의 트랜잭션이 끝나고 다음 트랜잭션을 수행시키면 데이터베이스의 일관성에 문제가 없지만, 데이터베이스는 공유를 목적으로 하기 때문에 가능한 많은 트랜잭션을 동시에 수행시켜야 한다
- 하지만 동시에 수행되는 트랜잭션은 다른 트랜잭션이 같은 데이터를 공유하고 있다는 사실을 모를 수 있기 때문에 일관성이 훼손될 수 있다
- 동시성 제어(concurrency control): 트랜잭션이 동시에 수행될 때, 일관성을 해치지 않도록 트랜잭션의 데이터 접근을 제어하는 DBMS의 기능
- 트랜잭션의 읽기/쓰기 시나리오
상황 트랜잭션 1 트랜잭션 2 발생 문제 동시 접근
상황 | 트랜잭션 1 | 트랜잭션 2 | 발생 문제 | 동시 접근 |
[상황 1] | 읽기 | 읽기 | 없음(읽기만 하면 아무 문제 없음) | 허용 |
[상황 2] | 읽기 | 쓰기 | 오손 읽기, 반복불가능 읽기, 유령 데이터 읽기 | 허용 혹은 불가 선택 |
[상황 3] | 쓰기 | 쓰기 | 갱신손실(절대 허용하면 안 됨) | 허용불가(LOCK을 이용) |
1. 갱신손실 문제
- 갱신손실(lost update) 문제: 두 개의 트랜잭션이 한 개의 데이터를 동시에 갱신할 때 발생한다
- 데이터베이스에서 절대 발생하면 안 되는 현상이다!
2. 락
- 갱신손실 문제를 해결하려면 상대방 트랜잭션이 데이터를 사용하는지 여부를 알 수 있는 규칙이 필요하다
- 자신이 데이터를 수정 중이라는 사실을 알리면 되는데, 알리는 방법으로 락(lock)이라는 잠금장치를 사용한다
- 락(lock): 트랜잭션이 데이터를 읽거나 수정할 때 데이터에 표시하는 잠금 장치
- 락을 이용하여 자신이 사용할 데이터를 잠그면 다른 트랜잭션은 잠금이 풀릴 때까지 기다려야 한다
- 락을 설정하면, 다른 트랜잭션은 자신이 원하는 락을 얻지 못하고 대기(wait)하고, 락이 해지(unlock)되어야 진행할 수 있다
- 락을 사용하면 데이터에 대한 갱신을 순차적으로 진행할 수 있기 때문에 갱신손실 문제를 해결할 수 있다
- 다른 트랜잭션을 대기 상태로 만드는 일은 사용자의 응답시간에 영향을 주기 때문에 가능한 최소화해야 한다
- 락의 유형
- 트랜잭션이 다루는 데이터(읽기만 하는 데이터, 읽고 쓰는 데이터, 쓰기만 하는 데이터)의 유형에 따라 락의 유형을 나눈다(읽기만 하는 데이터를 다루는 트랜잭션은 어느 정도 허용을 해도 문제가 없다)
- 공유락(LS, shared lock): 트랜잭션이 읽기를 할 때 사용하는 락
- 배타락(LX, exclusive lock): 읽기/쓰기를 할 때 사용하는 락
- 예시(p. 454): 데이터 X를 다루는 트랜잭션이 공유락과 배타락을 사용하는 규칙
- 데이터에 락이 걸려있으면 트랜잭션은 데이터에 락을 걸 수 있다
- 트랜잭션이 데이터 X를 읽기만 할 경우 LS(X)를 요청하고, 읽거나 쓰기를 할 경우 LX(X)를 요청한다
- 다른 트랜잭션이 데이터에 LS(X)를 걸어두면, LS(X)의 요청은 허용하고 LX(X)는 허용하지 않는다
- 다른 트랜잭션이 데이터에 LX(X)를 걸어두면, LS(X)와 LX(X) 모두 허용하지 않는다
- 트랜잭션이 락을 허용받지 못하면 대기 상태가 된다
- 락의 허용 관계를 나타낸 락 호환행렬(compatibility matrix)
요청 / 상태 | LS 상태 | LX 상태 |
LS 요청 | 허용 | 대기 |
LX 요청 | 대기 | 대기 |
2단계 락킹
- 락을 걸고 해제하는 시점에 제한을 두지 않으면 두 개의 트랜잭션이 동시에 실행될 때 데이터의 일관성이 깨질 수 있다 → 데이터에 락을 걸었다 풀고 다시 거는 중간 과정에 락의 해지 상태가 생기면서 다른 트랜잭션에게 중간 결과를 보일 수 있다 → 이를 방지하기 위해 2단계 락킹을 사용한다
- 2단계 락킹(2 phase locking) 기법: 트랜잭션이 락을 걸고 해제하는 시점을 2단계로 나눈다
- 확장단계(Growing phase, Expanding phase): 트랜잭션이 필요한 락을 획득하는 단계로, 이 단계에서는 이미 획득한 락을 해제하지 않는다
- 수축단계(Shrinking phase): 트랜잭션이 락을 해제하는 단계로, 이 단계에서는 새로운 락을 획득하지 않는다
- 데드락(deadlock, = 교착상태): 두 개 이상의 트랜잭션이 각각 자신의 데이터에 대하여 락을 획득하고 상대방 데이터에 대하여 락을 요청했을 때 무한 대기 상태에 빠지는 현상
- 일반적으로 데드락이 발생하면 DBMS는 트랜잭션 중 하나를 강제로 중지시키고, 나머지 트랜잭션은 정상적으로 실행된다. 이 때 중지시키는 트랜잭션에서 변경된 데이터는 원래 상태로 돌려놓는다
- 대기 그래프(wait-for-graph)를 그려서 데드락의 발생 여부를 판단할 수 있다
- 트랜잭션을 노드로, 락 요청을 화살표로 표현한다
- ex) 트랜잭션 T1이 트랜잭션 T2가 락을 걸고 있는 데이터를 요청하면 T1에서 T2로 향하는 화살표를 그린다
- 대기 그래프에서 사이클이 존재하면 데드락이 발생한 것이다
03. 트랜잭션 고립 수준
- 트랜잭션의 읽기/쓰기 시나리오의 [상황 2]를 락으로 해결하면 두 트랜잭션의 동시 진행 정도를 과도하게 막게 되므로, 동시성을 높이기 위해 좀 더 완화된 방법이 필요하다
1. 트랜잭션 동시 실행 문제
- [상황 2]의 트랜잭션 1은 읽기만 하므로 갱신손실 같은 심각한 문제가 발생하지 않지만, 오손 읽기(dirty read) 문제, 반복불가능 읽기(non-repeatable read) 문제, 유령 데이터 읽기(phantom read) 문제 등이 발생할 수 있다
- → 읽기만 하는 트랜잭션이 쓰기 트랜잭션에서 작업한 중간 데이터를 읽기 때문에 발생하는 문제이다
- 오손 읽기(dirty read, uncommitted dependency): 읽기 작업을 하는 트랜잭션 1이 쓰기 작업을 하는 트랜잭션 2가 작업한 중간 데이터를 읽어서 생기는 문제
- 작업 중인 트랜잭션 2가 어떤 이유로 작업을 철회(ROLLBACK)할 경우 트랜잭션 1은 무효가 된 데이터를 읽게 되고 잘못된 결과를 도출한다
- 반복불가능 읽기(non-repeatable read): 트랜잭션 1이 데이터를 읽고 트랜잭션 2가 데이터를 쓰고(갱신, UPDATE), 트랜잭션 1이 다시 한 번 데이터를 읽을 때 생기는 문제
- = 트랜잭션 1이 읽기 작업을 다시 한 번 반복할 경우 이전의 결과가 반복되지 않는 현상
- 유령데이터 읽기(phantom read): 트랜잭션 1이 데이터를 읽고 트랜잭션 2가 데이터를 쓰고(삽입, INSERT), 트랜잭션 1이 다시 한 번 데이터를 읽을 때 생기는 문제
- 트랜잭션 1이 읽기 작업을 다시 한 번 반복할 경우 이전에 없던 데이터(= 유령 데이터)가 나타나는 현상
2. 트랜잭션 고립 수준 명령어
- 트랜잭션 고립 수준 명령어(transaction isolation level instruction): 트랜잭션을 동시에 실행시키면서 락보다 좀 더 완화된 방법으로 문제를 해결하는 명령어
- 트랜잭션 고립 수준 표준 명령어와 발생 현상(ANSI 표준)
- READ UNCOMMITTED(Level=0)
- 고립 수준이 가장 낮은 명령어
- 자신의 데이터에 아무런 공유락을 걸지 않는다
- 배타락은 갱신손실 문제 대문에 걸어야 한다
- 다른 트랜잭션에 공유락과 배타락이 걸린 데이터를 대기하지 않고 읽는다
- 다른 트랜잭션이 COMMIT하지 않은 데이터를 읽을 수 있다 → 오손 페이지의 데이터를 읽게 된다
- SELECT 질의의 대상이 되는 테이블에 대해서 락을 설정하지 않은 것(NO LOCK)과 같다
- READ COMMITTED(Level=1)
- 오손 페이지의 참조를 피하기 위해 자신의 데이터를 읽는 동안 공유락을 걸지만, 트랜잭션이 끝나기 전에도 해지가능하다
- 다른 트랜잭션 데이터는 락 호환성 규칙에 따라 진행한다
- REPEATABLE READ(Level=2)
- 자신의 데이터에 설정된 공유락과 배타락을 트랜잭션이 종료할 때까지 유지하여 다른 트랜잭션이 자신의 데이터를 갱신(UPDATE)할 수 없도록 한다
- 다른 트랜잭션 데이터는 락 호환성 규칙에 따라 진행한다
- 다른 고립화 수준에 비해 데이터의 동시성이 낮아, 특별한 상황이 아니라면 사용하지 않는 것이 좋다
- MySQL은 공유락을 걸지 않고 최초 트랜잭션 SELECT 수행 시 SNAPSHOT을 만든 후 그 SNAPSHOT으로 SELECT를 수행하여, 다른 트랜잭션의 변경 시에도 동일한 결과를 유지한다
- SEREIALIZABLE(Level=3)
- 고립 수준이 가장 높은 명령어
- 실행 중인 트랜잭션은 다른 트랜잭션으로부터 완벽하게 분리된다
- 데이터 집합에 범위를 지어 잠금을 설정할 수 있기 때문에 다른 사용자가 데이터를 변경하려고 할 때 트랜잭션을 완벽하게 분리할 수 있다
- 네 가지 고립화 수준 중 제한이 가장 심하고 데이터의 동시성도 낮다
- SELECT 질의의 대상이 되는 테이블에 미리 배타락을 설정한 것과 같은 효과를 낸다
3. 트랜잭션 고립 수준 실습
- p.469 - 474 참고
04. 회복
- 회복(recovery): 데이터베이스에 장애가 발생했을 때 데이터베이스를 일관성 있는 상태로 되돌리는 DBMS의 기능
- 장애의 유형
- 시스템 충돌: 하드웨어 혹은 소프트웨어의 오류로 주기억장치가 손실되는 것으로, 처리 중인 프로그램과 데이터의 일부 혹은 전부가 손실된다
- 미디어 장애: 헤드 충돌이나 읽기 장애로 보조기억장치가 손실되는 것으로, 보조기억장치에 저장 중인 데이터의 일부 혹은 전부가 손실된다
- 응용 소프트웨어 오류: 데이터베이스에 접근하는 소프트웨어의 논리적인 오류로 트랜잭션의 수행이 실패하는 것이다
- 자연재해: 자연재해에 의해 컴퓨터 시스템이 손상되는 것
- 부주의 혹은 태업(sabotage): 운영자나 사용자의 부주의로 데이터가 손실되거나 의도적인 손상을 입는 것이다
1. 트랜잭션과 회복
- 트랜잭션은 회복의 단위이다
- 트랜잭션은 데이터의 변경 내용을 한순간에 데이터베이스에 기록하지 않고, 일단 변경한 내용(버퍼)을 로그(임시 디스크)에 기록한 후 데이터베이스에 반영한다
- DBMS의 회복 관리자(recovery manager)는 트랜잭션의 ACID 성질 중 원자성과 지속성을 보장하여 장애로부터 데이터베이스를 보호한다
- 장애가 발생하면 로그의 내용을 참조하여 트랜잭션의 변경 내용을 모두 반영하거나 아예 반영하지 않는 방법으로 원자성을 보장한다(지속성도 마찬가지다)
- 트랜잭션이 일단 COMMIT한 내용은 로그를 이용하여 반드시 데이터베이스에 기록한다
- 트랜잭션은 ‘시작 - 수행 - 부분완료 - 완료’ 과정을 거친다
- COMMIT
- 트랜잭션을 부분완료(partially committed)시키는 명령어로, 트랜잭션의 종료를 사용자나 다른 트랜잭션에게 알린다
- 이 단계를 거치면 트랜잭션이 변경한 내용이 버퍼뿐만 아니라 재해에 대비하여 로그(임시 디스크)에도 저장된다
- 이후 DBMS가 다른 작업의 상황을 보면서 버퍼의 내용을 하드디스크에 기록하고 기록이 끝나면 최종적으로 완료한다
- 만약 COMMIT 문이 생략되었다면, DBMS가 알아서 이 문장을 생성했다고 보면 된다
- 로그에 변경 내용을 기록한 후에는 부분완료 이후의 남은 부분을 COMMIT 전에 수행할 수도 있고(즉시갱신 방법), COMMIT 후에만 하도록 할 수도 있다(지연갱신 방법)
- COMMIT
- 트랜잭션의 수행 과정 예시
START TRANSACTION
# 1) 박지성 계좌를 읽어온다
# 2) 김연아 계좌를 읽어온다
# 잔고 확인
# 3) 예금인출 박지성
UPDATE Customer
SET balance = balance - 10000
WHERE name = '박지성';
# 4) 예금입금 김연아
UPDATE Customer
SET balance = balance + 10000
WHERE name = '김연아';
COMMIT /* 부분 완료 */
# 5) 박지성 계좌를 기록한다
# 6) 김연아 계좌를 기록한다
- 트랜잭션이 시작하면 수행(active) 상태가 된다
- 정상적으로 수행되면 COMMIT 문을 만나 최종완료된다
- 만약 수행 중에 문제가 생겨 완료 전에 실패하면 취소(abort) 과정을 거쳐 이제까지 진행한 작업을 거꾸로 돌려놓는다. 변경된 데이터 중 혹시 데이터베이스에 이미 기록된 데이터가 있으면 로그를 이용하여 되돌린다
- 부분완료를 했으나 실패가 일어난 경우라면, 취소 과정을 거쳐 이제까지 진행한 작업을 거꾸로 돌려놓는다. 부분완료 후 실패하는 경우는 컴퓨터시스템 장애, 트랜잭션 오류, 데드락 등 여러 원인이 있을 수 있다.
2. 로그 파일
- 로그 파일(log file): 트랜잭션이 수행 중이거나, 수행이 종료된 후 발생하는 데이터베이스 손실을 방지하기 위해 트랜잭션의 데이터베이스 기록을 추적할 때 DBMS가 사용하는 것
- 트랜잭션이 반영한 모든 데이터의 변경사항을 데이터베이스에 기록하기 전에 미리 기록해두는 별도의 데이터베이스이다
- 안전한 하드디스크에 저장되며 전원과 관계없이 기록이 남아있다
- 로그의 구조
- 로그 타입: 트랜잭션의 연산 타입으로 START, INSERT, UPDATE, DELETE, ABORT, COMMIT 등이 있다
- 수정 전 값: 데이터의 변경 전 값
- 수정 후 값: 연산의 결과로 변경된 값
<트랜잭션번호, 로그 타입, 데이터 항목 이름, 수정 전 값, 수정 후 값>
- 수행 중에 변경된 데이터는 주기억장치의 버퍼에 기록된다
- 데이터의 변경이 일어날 때마다 변경 내용은 로그 파일에 저장된다
- 부분완료에 도달하면 변경된 데이터는 모두 로그 파일에 기록되어 있다
- 버퍼의 변경된 데이터는 트랜잭션 시작 이후 종료까지 임의의 시점에 DBMS가 운영체제의 도움을 받아 데이터베이스에 기록한다
- 부분완료 후의 수행 과정 중에 시스템이 정지되어도, 시스템을 다시 시작한 다음 로그 파일에 기록된 내용을 참조하여 데이터베이스에 반영할 수 있기 때문에 문제없다
3. 로그 파일을 이용한 회복
- 시스템 운영 중 장애가 발생하여 시스템이 다시 가동되었을 때 DBMS는 로그 파일을 먼저 살펴본다
- 트랜잭션이 종료되었는지 혹은 중단되었는지 여부를 판단→ 중단된 트랜잭션은 없던 일로 되돌리기 위해 취소(UNDO)를 진행한다
- 이 두 작업 모두 트랜잭션이 로그 데이터베이스에 기록한 모든 값에 대해 (변경 전 값, 변경 후 값) 중 어느 하나를 데이터베이스에 맞는 값으로 수정하는 작업이다
- → 종료된 트랜잭션은 종료를 확종하기 위해 재실행(REDO)를 진행한다
- 트랜잭션이 종료되었는지 혹은 중단되었는지 여부를 판단→ 중단된 트랜잭션은 없던 일로 되돌리기 위해 취소(UNDO)를 진행한다
트랜잭션의 재실행(REDO)
- 장애가 발생한 후 시스템을 다시 가동했을 때, 로그 파일에 트랜잭션의 시작(START)와 종료(COMMIT)가 있는 경우
- COMMIT 연산이 로그에 있다는 것 = 트랜잭션이 모두 완료되었다는 의미
- 다만, 변경 내용이 버퍼에서 데이터베이스에 기록되지 않았을 가능성이 있다
- → 로그를 보면서 트랜잭션이 변경한 내용을 데이터베이스에 다시 기록하는 과정이 필요하다(REDO)
트랜잭션의 취소(UNDO)
- 장애가 발생한 후 시스템을 다시 가동했을 때, 로그 파일에 트랜잭션의 시작(START)만 있고 종료(COMMIT)가 없는 경우
- COMMIT 연산이 로그에 없다는 것 = 트랜잭션이 완료되지 못했다는 의미
- → 트랜잭션이 한 일을 모두 취소해야 한다
- 완료하지 못했지만 버퍼의 변경 내용이 데이터베이스에 기록되어 있을 가능성이 있기 때문에 로그를 보면서 트랜잭션이 변경한 내용을 데이터베이스에서 원상복구시켜야 한다(UNDO)
즉시갱신과 지연갱신
- REDO와 UNDO는 부분완료 전에라도 트랜잭션이 변경한 내용 일부가 데이터베이스에 기록될 수 있음을 가정한 방법이다
- 이와 달리 트랜잭션이 반드시 부분완료된 후 변경 내용을 데이터베이스에 기록하는 방법이 즉시갱신과 지연갱신이다
- 즉시갱신(immediate update)
- ‘버퍼 → 로그 파일’, ‘버퍼 → 데이터베이스’ 작업이 부분완료 전에 동시에 진행될 수 있다
- 부분완료 전에 버퍼의 갱신 데이터는 로그에 기록이 진행된 상태이며 부분완료 전에 버퍼의 일부 내용이 실제 데이터베이스에 반영이 될 수 있다
- 지연갱신(deferred update)
- ‘버퍼 → 로그 파일’이 모두 끝난 후 부분완료를 하고 이후 ‘버퍼 → 데이터베이스’ 작업을 진행하는 방법
- 부분완료 전에는 갱신 내용이 실제 데이터베이스에 반영되지 않은 상태이다
- 즉시갱신과 마찬가지로 부분완료가 되면 최소한 버퍼의 갱신 데이터는 로그에 모두 기록이 끝난 상태지만, 데이터베이스에 반영은 되지 않은 상태이다
- 데이터베이스에 반영하는 작업은 지연되지만, 장애가 발생할 경우 로그에 START만 나타나는 트랜잭션은 UNDO 작업을 할 필요가 없다
4. 체크포인트를 이용한 회복
- 로그를 이용한 회복은 시스템에 장애가 일어났을 때 어느 시점까지 되돌아가야 하는지 알 수 없다
- 체크포인트(checkpoint, 검사점): 회복 시 많은 양의 로그를 검색하고 갱신하는 시간을 줄이기 위해 몇 십 분 단위로 데이터베이스와 트랜잭션 로그 파일을 동기화한 후 동기화한 시점을 로그 파일에 기록해두는 방법이나 그 시점
- 체크포인트 시점에 진행하는 작업들
- 주기억장치의 로그 레코드를 모두 모아 하드디스크의 로그 파일에 저장한다
- 버퍼에 있는 변경된 내용을 하드디스크의 데이터베이스에 저장한다(즉시갱신 경우)
- 체크포인트를 로그 파일에 표시한다
- 체크포인트 시점에 진행하는 작업들
- 체크포인트가 있을 때 트랜잭션의 로그 기록에 따라 회복하는 방법
- 체크포인트 이전에 COMMIT 기록이 있는 트랜잭션의 경우
- 아무 작업이 필요 없다(로그에 체크포인트가 나타나는 시점은 이미 변경 내용이 체크포인트에 의해 데이터베이스에 모두 기록된 후이기 때문(즉시갱신, 지연갱신))
- 체크포인트 이후에 COMMIT 기록이 있는 트랜잭션의 경우
- REDO(T)를 진행한다(체크포인트 이후에 변경 내용이 데이터베이스에 반영되지 않았을 가능성이 있기 때문)
- 체크포인트 이후에 COMMIT 기록이 없는 트랜잭션의 경우
- 즉시갱신 방법을 사용했을 때: UNDO(T)를 진행한다(버퍼의 내용이 반영됐을 수도 있기 때문)
- 지연갱신 방법을 사용했을 때: 아무것도 할 필요 없다(지연갱신 방법은 COMMIT 이전에는 버퍼의 내용을 데이터베이스에 반영하지 않기 때문)
- 체크포인트 이전에 COMMIT 기록이 있는 트랜잭션의 경우
'Courses > 데이터베이스' 카테고리의 다른 글
02_Relational Model (0) | 2025.01.22 |
---|---|
01_Introduction to Database (1) | 2025.01.22 |
데이터베이스 개론과 실습 (MySQL로 배우는) | Chapter 07 정규화 (0) | 2025.01.16 |
데이터베이스 개론과 실습 (MySQL로 배우는) | Chapter 06 (2) | 2025.01.16 |
데이터베이스 개론과 실습 (MySQL로 배우는) | Chapter 05: 데이터베이스 프로그래밍 (0) | 2025.01.16 |