Courses/데이터베이스

데이터베이스 개론과 실습 (MySQL로 배우는) | Chapter 08: 트랜잭션, 동시성 제어, 회복

noweahct 2025. 1. 16. 11:59

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) 김연아 계좌를 기록한다
  • 트랜잭션은 데이터베이스에 저장된 테이블을 읽어와 주기억장치 버퍼에 저장하고, 버퍼에 저장된 데이터를 수정한 후 최종적으로 데이터베이스에 다시 저장한다
  • 세부 과정
    1. A 계좌(박지성)의 값을 하드디스크(데이터베이스)에서 주기억장치 버퍼로 읽어온다
    2. B 계좌(김연아)의 값을 하드디스크(데이터베이스)에서 주기억장치 버퍼로 읽어온다
    3. A 계좌(박지성)에서 10,000원을 인출한 값을 저장한다
    4. B 계좌(김연아)에서 10,000원을 입금한 값을 저장한다
    5. A 계좌(박지성)의 값을 주기억장치 버퍼에서 하드디스크(데이터베이스)에 기록한다
    6. 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 성질
    1. Atomicity(원자성)
    2. Consistency(일관성)
    3. Isolation(고립성)
    4. 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 성질을 유지할 수 있도록 지원한다

  1. 원자성을 유지하기 위해 회복(복구) 관리자 프로그램을 작동시킨다
    • 회복 관리자 프로그램은 데이터베이스가 변경한 내용을 로그에 기록하고 있다가 트랜잭션에 문제가 생겼을 때 원래 상태로 되돌린다
  2. 일관성을 유지하기 위해 무결성 제약조건을 활용한다
    • 트랜잭션 수행 시 데이터에 변경이 가해지면 미리 정의해둔 무결성 제약조건을 검사하여 일관성이 깨지는 것을 막는다
    • 두 개의 트랜잭션이 동시에 수행될 때 트랜잭션 간에 간섭으로 일관성이 깨지는 현상은 무결성 제약조건을 검사하는 것으로 해결할 수 없고, 동시성 제어 알고리즘을 작동시켜야 한다
  3. 고립성을 유지하기 위해 동시성 제어 알고리즘을 작동시킨다
    • 두 개의 트랜잭션이 동시에 수행될 때 간섭에 의해 데이터 값이 손상되면 고립성이 깨지고, 이 경우 동시성 제어 알고리즘을 작동시켜 여러 트랜잭션이 동시에 같은 데이터를 접근할 때 한 트랜잭션씩 순서대로 접근하는 것처럼 제어한다
  4. 지속성을 유지하기 위해 회복 관리자 프로그램을 이용한다
    • 회복 관리자 프로그램은 데이터베이스가 변경한 내용을 로그로 기록하고 있다가 트랜잭션에 문제가 있을 때 원래 상태로 되돌린다

02. 동시성 제어

  • 한 개의 트랜잭션이 끝나고 다음 트랜잭션을 수행시키면 데이터베이스의 일관성에 문제가 없지만, 데이터베이스는 공유를 목적으로 하기 때문에 가능한 많은 트랜잭션을 동시에 수행시켜야 한다
  • 하지만 동시에 수행되는 트랜잭션은 다른 트랜잭션이 같은 데이터를 공유하고 있다는 사실을 모를 수 있기 때문에 일관성이 훼손될 수 있다
  • 동시성 제어(concurrency control): 트랜잭션이 동시에 수행될 때, 일관성을 해치지 않도록 트랜잭션의 데이터 접근을 제어하는 DBMS의 기능
  • 트랜잭션의 읽기/쓰기 시나리오

상황 트랜잭션 1 트랜잭션 2 발생 문제 동시 접근

상황 트랜잭션 1 트랜잭션 2 발생 문제 동시 접근
[상황 1] 읽기 읽기 없음(읽기만 하면 아무 문제 없음) 허용
[상황 2] 읽기 쓰기 오손 읽기, 반복불가능 읽기, 유령 데이터 읽기 허용 혹은 불가 선택
[상황 3] 쓰기 쓰기 갱신손실(절대 허용하면 안 됨) 허용불가(LOCK을 이용)

1. 갱신손실 문제

  • 갱신손실(lost update) 문제: 두 개의 트랜잭션이 한 개의 데이터를 동시에 갱신할 때 발생한다
    • 데이터베이스에서 절대 발생하면 안 되는 현상이다!

2. 락

  • 갱신손실 문제를 해결하려면 상대방 트랜잭션이 데이터를 사용하는지 여부를 알 수 있는 규칙이 필요하다
    • 자신이 데이터를 수정 중이라는 사실을 알리면 되는데, 알리는 방법으로 락(lock)이라는 잠금장치를 사용한다
  • 락(lock): 트랜잭션이 데이터를 읽거나 수정할 때 데이터에 표시하는 잠금 장치
    • 락을 이용하여 자신이 사용할 데이터를 잠그면 다른 트랜잭션은 잠금이 풀릴 때까지 기다려야 한다
    • 락을 설정하면, 다른 트랜잭션은 자신이 원하는 락을 얻지 못하고 대기(wait)하고, 락이 해지(unlock)되어야 진행할 수 있다
  • 락을 사용하면 데이터에 대한 갱신을 순차적으로 진행할 수 있기 때문에 갱신손실 문제를 해결할 수 있다
  • 다른 트랜잭션을 대기 상태로 만드는 일은 사용자의 응답시간에 영향을 주기 때문에 가능한 최소화해야 한다
  • 락의 유형
    • 트랜잭션이 다루는 데이터(읽기만 하는 데이터, 읽고 쓰는 데이터, 쓰기만 하는 데이터)의 유형에 따라 락의 유형을 나눈다(읽기만 하는 데이터를 다루는 트랜잭션은 어느 정도 허용을 해도 문제가 없다)
    1. 공유락(LS, shared lock): 트랜잭션이 읽기를 할 때 사용하는 락
    2. 배타락(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단계로 나눈다
    1. 확장단계(Growing phase, Expanding phase): 트랜잭션이 필요한 락을 획득하는 단계로, 이 단계에서는 이미 획득한 락을 해제하지 않는다
    2. 수축단계(Shrinking phase): 트랜잭션이 락을 해제하는 단계로, 이 단계에서는 새로운 락을 획득하지 않는다
  • 데드락(deadlock, = 교착상태): 두 개 이상의 트랜잭션이 각각 자신의 데이터에 대하여 락을 획득하고 상대방 데이터에 대하여 락을 요청했을 때 무한 대기 상태에 빠지는 현상
    • 일반적으로 데드락이 발생하면 DBMS는 트랜잭션 중 하나를 강제로 중지시키고, 나머지 트랜잭션은 정상적으로 실행된다. 이 때 중지시키는 트랜잭션에서 변경된 데이터는 원래 상태로 돌려놓는다
    • 대기 그래프(wait-for-graph)를 그려서 데드락의 발생 여부를 판단할 수 있다
      • 트랜잭션을 노드로, 락 요청을 화살표로 표현한다
      • ex) 트랜잭션 T1이 트랜잭션 T2가 락을 걸고 있는 데이터를 요청하면 T1에서 T2로 향하는 화살표를 그린다
      • 대기 그래프에서 사이클이 존재하면 데드락이 발생한 것이다


03. 트랜잭션 고립 수준

  • 트랜잭션의 읽기/쓰기 시나리오의 [상황 2]를 락으로 해결하면 두 트랜잭션의 동시 진행 정도를 과도하게 막게 되므로, 동시성을 높이기 위해 좀 더 완화된 방법이 필요하다

1. 트랜잭션 동시 실행 문제

  • [상황 2]의 트랜잭션 1은 읽기만 하므로 갱신손실 같은 심각한 문제가 발생하지 않지만, 오손 읽기(dirty read) 문제, 반복불가능 읽기(non-repeatable read) 문제, 유령 데이터 읽기(phantom read) 문제 등이 발생할 수 있다
  • → 읽기만 하는 트랜잭션이 쓰기 트랜잭션에서 작업한 중간 데이터를 읽기 때문에 발생하는 문제이다
  1. 오손 읽기(dirty read, uncommitted dependency): 읽기 작업을 하는 트랜잭션 1이 쓰기 작업을 하는 트랜잭션 2가 작업한 중간 데이터를 읽어서 생기는 문제
    • 작업 중인 트랜잭션 2가 어떤 이유로 작업을 철회(ROLLBACK)할 경우 트랜잭션 1은 무효가 된 데이터를 읽게 되고 잘못된 결과를 도출한다
  2. 반복불가능 읽기(non-repeatable read): 트랜잭션 1이 데이터를 읽고 트랜잭션 2가 데이터를 쓰고(갱신, UPDATE), 트랜잭션 1이 다시 한 번 데이터를 읽을 때 생기는 문제
  3. = 트랜잭션 1이 읽기 작업을 다시 한 번 반복할 경우 이전의 결과가 반복되지 않는 현상
  4. 유령데이터 읽기(phantom read): 트랜잭션 1이 데이터를 읽고 트랜잭션 2가 데이터를 쓰고(삽입, INSERT), 트랜잭션 1이 다시 한 번 데이터를 읽을 때 생기는 문제
    • 트랜잭션 1이 읽기 작업을 다시 한 번 반복할 경우 이전에 없던 데이터(= 유령 데이터)가 나타나는 현상

2. 트랜잭션 고립 수준 명령어

  • 트랜잭션 고립 수준 명령어(transaction isolation level instruction): 트랜잭션을 동시에 실행시키면서 락보다 좀 더 완화된 방법으로 문제를 해결하는 명령어
  • 트랜잭션 고립 수준 표준 명령어와 발생 현상(ANSI 표준)

  1. READ UNCOMMITTED(Level=0)
    • 고립 수준이 가장 낮은 명령어
    • 자신의 데이터에 아무런 공유락을 걸지 않는다
    • 배타락은 갱신손실 문제 대문에 걸어야 한다
    • 다른 트랜잭션에 공유락과 배타락이 걸린 데이터를 대기하지 않고 읽는다
    • 다른 트랜잭션이 COMMIT하지 않은 데이터를 읽을 수 있다 → 오손 페이지의 데이터를 읽게 된다
    • SELECT 질의의 대상이 되는 테이블에 대해서 락을 설정하지 않은 것(NO LOCK)과 같다
  2. READ COMMITTED(Level=1)
    • 오손 페이지의 참조를 피하기 위해 자신의 데이터를 읽는 동안 공유락을 걸지만, 트랜잭션이 끝나기 전에도 해지가능하다
    • 다른 트랜잭션 데이터는 락 호환성 규칙에 따라 진행한다
  3. REPEATABLE READ(Level=2)
    • 자신의 데이터에 설정된 공유락과 배타락을 트랜잭션이 종료할 때까지 유지하여 다른 트랜잭션이 자신의 데이터를 갱신(UPDATE)할 수 없도록 한다
    • 다른 트랜잭션 데이터는 락 호환성 규칙에 따라 진행한다
    • 다른 고립화 수준에 비해 데이터의 동시성이 낮아, 특별한 상황이 아니라면 사용하지 않는 것이 좋다
    • MySQL은 공유락을 걸지 않고 최초 트랜잭션 SELECT 수행 시 SNAPSHOT을 만든 후 그 SNAPSHOT으로 SELECT를 수행하여, 다른 트랜잭션의 변경 시에도 동일한 결과를 유지한다
  4. SEREIALIZABLE(Level=3)
    • 고립 수준이 가장 높은 명령어
    • 실행 중인 트랜잭션은 다른 트랜잭션으로부터 완벽하게 분리된다
    • 데이터 집합에 범위를 지어 잠금을 설정할 수 있기 때문에 다른 사용자가 데이터를 변경하려고 할 때 트랜잭션을 완벽하게 분리할 수 있다
    • 네 가지 고립화 수준 중 제한이 가장 심하고 데이터의 동시성도 낮다
    • SELECT 질의의 대상이 되는 테이블에 미리 배타락을 설정한 것과 같은 효과를 낸다
     

3. 트랜잭션 고립 수준 실습

  • p.469 - 474 참고

04. 회복

  • 회복(recovery): 데이터베이스에 장애가 발생했을 때 데이터베이스를 일관성 있는 상태로 되돌리는 DBMS의 기능
  • 장애의 유형
    1. 시스템 충돌: 하드웨어 혹은 소프트웨어의 오류로 주기억장치가 손실되는 것으로, 처리 중인 프로그램과 데이터의 일부 혹은 전부가 손실된다
    2. 미디어 장애: 헤드 충돌이나 읽기 장애로 보조기억장치가 손실되는 것으로, 보조기억장치에 저장 중인 데이터의 일부 혹은 전부가 손실된다
    3. 응용 소프트웨어 오류: 데이터베이스에 접근하는 소프트웨어의 논리적인 오류로 트랜잭션의 수행이 실패하는 것이다
    4. 자연재해: 자연재해에 의해 컴퓨터 시스템이 손상되는 것
    5. 부주의 혹은 태업(sabotage): 운영자나 사용자의 부주의로 데이터가 손실되거나 의도적인 손상을 입는 것이다

1. 트랜잭션과 회복

  • 트랜잭션은 회복의 단위이다
  • 트랜잭션은 데이터의 변경 내용을 한순간에 데이터베이스에 기록하지 않고, 일단 변경한 내용(버퍼)을 로그(임시 디스크)에 기록한 후 데이터베이스에 반영한다
  • DBMS의 회복 관리자(recovery manager)는 트랜잭션의 ACID 성질 중 원자성과 지속성을 보장하여 장애로부터 데이터베이스를 보호한다
    • 장애가 발생하면 로그의 내용을 참조하여 트랜잭션의 변경 내용을 모두 반영하거나 아예 반영하지 않는 방법으로 원자성을 보장한다(지속성도 마찬가지다)
    • 트랜잭션이 일단 COMMIT한 내용은 로그를 이용하여 반드시 데이터베이스에 기록한다
  • 트랜잭션은 ‘시작 - 수행 - 부분완료 - 완료’ 과정을 거친다
    • COMMIT
      • 트랜잭션을 부분완료(partially committed)시키는 명령어로, 트랜잭션의 종료를 사용자나 다른 트랜잭션에게 알린다
      • 이 단계를 거치면 트랜잭션이 변경한 내용이 버퍼뿐만 아니라 재해에 대비하여 로그(임시 디스크)에도 저장된다
    • 이후 DBMS가 다른 작업의 상황을 보면서 버퍼의 내용을 하드디스크에 기록하고 기록이 끝나면 최종적으로 완료한다
      • 만약 COMMIT 문이 생략되었다면, DBMS가 알아서 이 문장을 생성했다고 보면 된다
    • 로그에 변경 내용을 기록한 후에는 부분완료 이후의 남은 부분을 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) 김연아 계좌를 기록한다
  1. 트랜잭션이 시작하면 수행(active) 상태가 된다
  2. 정상적으로 수행되면 COMMIT 문을 만나 최종완료된다
  3. 만약 수행 중에 문제가 생겨 완료 전에 실패하면 취소(abort) 과정을 거쳐 이제까지 진행한 작업을 거꾸로 돌려놓는다. 변경된 데이터 중 혹시 데이터베이스에 이미 기록된 데이터가 있으면 로그를 이용하여 되돌린다
  4. 부분완료를 했으나 실패가 일어난 경우라면, 취소 과정을 거쳐 이제까지 진행한 작업을 거꾸로 돌려놓는다. 부분완료 후 실패하는 경우는 컴퓨터시스템 장애, 트랜잭션 오류, 데드락 등 여러 원인이 있을 수 있다.

2. 로그 파일

  • 로그 파일(log file): 트랜잭션이 수행 중이거나, 수행이 종료된 후 발생하는 데이터베이스 손실을 방지하기 위해 트랜잭션의 데이터베이스 기록을 추적할 때 DBMS가 사용하는 것
    • 트랜잭션이 반영한 모든 데이터의 변경사항을 데이터베이스에 기록하기 전에 미리 기록해두는 별도의 데이터베이스이다
    • 안전한 하드디스크에 저장되며 전원과 관계없이 기록이 남아있다
    • 로그의 구조
      • 로그 타입: 트랜잭션의 연산 타입으로 START, INSERT, UPDATE, DELETE, ABORT, COMMIT 등이 있다
      • 수정 전 값: 데이터의 변경 전 값
      • 수정 후 값: 연산의 결과로 변경된 값
<트랜잭션번호, 로그 타입, 데이터 항목 이름, 수정 전 값, 수정 후 값>

 

  • 수행 중에 변경된 데이터는 주기억장치의 버퍼에 기록된다
  • 데이터의 변경이 일어날 때마다 변경 내용은 로그 파일에 저장된다
  • 부분완료에 도달하면 변경된 데이터는 모두 로그 파일에 기록되어 있다
  • 버퍼의 변경된 데이터는 트랜잭션 시작 이후 종료까지 임의의 시점에 DBMS가 운영체제의 도움을 받아 데이터베이스에 기록한다
  • 부분완료 후의 수행 과정 중에 시스템이 정지되어도, 시스템을 다시 시작한 다음 로그 파일에 기록된 내용을 참조하여 데이터베이스에 반영할 수 있기 때문에 문제없다

3. 로그 파일을 이용한 회복

  • 시스템 운영 중 장애가 발생하여 시스템이 다시 가동되었을 때 DBMS는 로그 파일을 먼저 살펴본다
    • 트랜잭션이 종료되었는지 혹은 중단되었는지 여부를 판단→ 중단된 트랜잭션은 없던 일로 되돌리기 위해 취소(UNDO)를 진행한다
      • 이 두 작업 모두 트랜잭션이 로그 데이터베이스에 기록한 모든 값에 대해 (변경 전 값, 변경 후 값) 중 어느 하나를 데이터베이스에 맞는 값으로 수정하는 작업이다
    • → 종료된 트랜잭션은 종료를 확종하기 위해 재실행(REDO)를 진행한다

트랜잭션의 재실행(REDO)

  • 장애가 발생한 후 시스템을 다시 가동했을 때, 로그 파일에 트랜잭션의 시작(START)와 종료(COMMIT)가 있는 경우
    • COMMIT 연산이 로그에 있다는 것 = 트랜잭션이 모두 완료되었다는 의미
    • 다만, 변경 내용이 버퍼에서 데이터베이스에 기록되지 않았을 가능성이 있다
    • → 로그를 보면서 트랜잭션이 변경한 내용을 데이터베이스에 다시 기록하는 과정이 필요하다(REDO)

트랜잭션의 취소(UNDO)

  • 장애가 발생한 후 시스템을 다시 가동했을 때, 로그 파일에 트랜잭션의 시작(START)만 있고 종료(COMMIT)가 없는 경우
    • COMMIT 연산이 로그에 없다는 것 = 트랜잭션이 완료되지 못했다는 의미
    • → 트랜잭션이 한 일을 모두 취소해야 한다
    • 완료하지 못했지만 버퍼의 변경 내용이 데이터베이스에 기록되어 있을 가능성이 있기 때문에 로그를 보면서 트랜잭션이 변경한 내용을 데이터베이스에서 원상복구시켜야 한다(UNDO)

즉시갱신과 지연갱신

  • REDO와 UNDO는 부분완료 전에라도 트랜잭션이 변경한 내용 일부가 데이터베이스에 기록될 수 있음을 가정한 방법이다
  • 이와 달리 트랜잭션이 반드시 부분완료된 후 변경 내용을 데이터베이스에 기록하는 방법이 즉시갱신과 지연갱신이다
  • 즉시갱신(immediate update)
    • ‘버퍼 → 로그 파일’, ‘버퍼 → 데이터베이스’ 작업이 부분완료 전에 동시에 진행될 수 있다
    • 부분완료 전에 버퍼의 갱신 데이터는 로그에 기록이 진행된 상태이며 부분완료 전에 버퍼의 일부 내용이 실제 데이터베이스에 반영이 될 수 있다
  • 지연갱신(deferred update)
    • ‘버퍼 → 로그 파일’이 모두 끝난 후 부분완료를 하고 이후 ‘버퍼 → 데이터베이스’ 작업을 진행하는 방법
    • 부분완료 전에는 갱신 내용이 실제 데이터베이스에 반영되지 않은 상태이다
    • 즉시갱신과 마찬가지로 부분완료가 되면 최소한 버퍼의 갱신 데이터는 로그에 모두 기록이 끝난 상태지만, 데이터베이스에 반영은 되지 않은 상태이다
    • 데이터베이스에 반영하는 작업은 지연되지만, 장애가 발생할 경우 로그에 START만 나타나는 트랜잭션은 UNDO 작업을 할 필요가 없다

4. 체크포인트를 이용한 회복

  • 로그를 이용한 회복은 시스템에 장애가 일어났을 때 어느 시점까지 되돌아가야 하는지 알 수 없다
  • 체크포인트(checkpoint, 검사점): 회복 시 많은 양의 로그를 검색하고 갱신하는 시간을 줄이기 위해 몇 십 분 단위로 데이터베이스와 트랜잭션 로그 파일을 동기화한 후 동기화한 시점을 로그 파일에 기록해두는 방법이나 그 시점
    • 체크포인트 시점에 진행하는 작업들
      1. 주기억장치의 로그 레코드를 모두 모아 하드디스크의 로그 파일에 저장한다
      2. 버퍼에 있는 변경된 내용을 하드디스크의 데이터베이스에 저장한다(즉시갱신 경우)
      3. 체크포인트를 로그 파일에 표시한다
  • 체크포인트가 있을 때 트랜잭션의 로그 기록에 따라 회복하는 방법
    • 체크포인트 이전에 COMMIT 기록이 있는 트랜잭션의 경우
      • 아무 작업이 필요 없다(로그에 체크포인트가 나타나는 시점은 이미 변경 내용이 체크포인트에 의해 데이터베이스에 모두 기록된 후이기 때문(즉시갱신, 지연갱신))
    • 체크포인트 이후에 COMMIT 기록이 있는 트랜잭션의 경우
      • REDO(T)를 진행한다(체크포인트 이후에 변경 내용이 데이터베이스에 반영되지 않았을 가능성이 있기 때문)
    • 체크포인트 이후에 COMMIT 기록이 없는 트랜잭션의 경우
      • 즉시갱신 방법을 사용했을 때: UNDO(T)를 진행한다(버퍼의 내용이 반영됐을 수도 있기 때문)
      • 지연갱신 방법을 사용했을 때: 아무것도 할 필요 없다(지연갱신 방법은 COMMIT 이전에는 버퍼의 내용을 데이터베이스에 반영하지 않기 때문)