Transaction

  • 트랜잭션(Transaction): DBMS가 데이터베이스를 다룰 때, 사용하는 작업(프로그램) 단위.

  • 데이터베이스의 무결성을 유지하기 위해 ACID(원자성, 일관성, 고립성, 지속성) 성질을 가진다.

  • DBMS는 이 성질을 유지할 수 있도록 지원한다.

01. 트랜잭션

01) 개념

  • 트랜잭션이란, DBMS에서 다루는 논리적인 작업의 단위이다.

  • 데이터베이스에서 트랜잭션을 정의하는 이유

    • 데이터베이스에서 데이터를 다룰때 장애가 일어나는 경우, 데이터를 복구하는 작업의 단위가 된다.

    • 데이터베이스에서 여러 작업이 동시에 같은 데이터를 다룰 때, 이 작업을 서로 분리하는 단위가 된다.

  • 트렌잭션은 전체가 수행되거나, 또는 전혀 수행되지 않아야 한다. (all or nothing)

  • 예시

    START TRANSACTION 
        update customer set value = value -1000 where name like '미니'; --1번 SQL
        update customer set value = value -2000 where name like '혀니'; --2번 SQL
    commit
    • transaction을 시작하면, 디스크에 저장된 해당 데이터를 읽어와 주기억장치(메모리) 버퍼 영역에 올려둔다.

    • 버퍼 영역에서 1,2번 SQL문을 수행하고 저장.

    • DBMS가 책임지고 버퍼에서 디스크영역에 저장을한다.

    • 이렇게 함으로써, DBMS가 동시에 많은 트랜잭션을 수행할 때, 트랜잭션이 하드디스크에 개별 접근하는 것을 피하고, 일괄적으로 디스크에 접근 처리 함으로써, 사용자에게 빠른 응답성을 보장할 수가 있다.

02) ACID

  • 원자성(Atomicity): 트랜잭션에 포함된 작업은 전부 수행되거나, 아니면 전부 수행되지 않아야한다. (all or nothing)

  • 일관성(Consistency): 트랜잭션을 수행하기 전, 후의 데이터베이스는 항상 일관된 상태를 유지해야한다.

  • 고립성(Isolation): 수행중인 트랜잭션에 다른 트랜잭션이 끼어들어 변경 중인 데이터 값을 훼손하는 일이 없어야한다.

  • 지속성(Durability): 수행을 성공적으로 완료한 트랜잭션은 변경한 데이터를 영구히 저장해야한다. 저장된 데이터 베이스는 저장 직후 혹은 어느 때나 발생할 수 있는 장애, 오류, 정전 등에 영향을 받지 않아야한다.

원자성

  • 트랜잭션이 원자처럼 더이상 쪼개지지 않는 하나의 프로그램 단위로 동작해야한다는 의미.

  • 즉, 일부만 수행되는 일이 없도록 전부 수행되거나 아예 수행되지 않아야한다.

  • Transaction control language (TCL)

    표준명령어

    문법

    설명

    START TRANSACTION

    START TRANSACTION

    트랜잭션 시작

    COMMIT

    COMMIT

    트랜잭션 종료

    ROLLBACK

    ROLLBACK {TO }

    트랜젝션을 전체 혹은 까지 무효화

    SAVE

    SAVEPOINT

    를 만듬

  • 트랜잭션 시작과 끝

    • 시작을 할리는 표준 명령어: START TRANSACTION

      • MySQL에서는

        • SET TRANSACTION NAME <이름>

        • 데이터를 변경하는 SQL문이 나오면 자동으로 트랜잭션이 시작됨.

    • 종료

      • COMMIT 혹은 ROLLBACK

      • DDL (CREATE. ALTER. DROP. RENAME. TRUNCATE...) 만나면 자동종료

일관성

  • 트랜잭션 수행 전과 후의 데이터베이스는 항상 일관된 상태여야한다.

  • 테이블 생성 시, CREATE 문과 ALTER문의 무결성 제약조건을 통해 명시된다.

고립성

  • 데이터베이스는 공유가 목적이므로 여러 트랜잭션이 동시 수행된다.

  • 이 때, 각 트랜잭션은 다른 트랜잭션에 방해받지 않고 독립적으로 작업을 수행한다.

  • 여러 트랜잭션이 동시에 수행될 때, 상호간섭이나 데이터 충돌이 일어나지 않는 현상.

  • 변경중인 임시 데이터를 다른 트랜잭션이 읽거나 쓰려할 때 제어하는 작업이 필요하다.

  • 위 그럼처럼, t1 시간에 트랜잭션 2, 3이 동시 접근한 테이블 B의 데이터 일관성을 훼손하지 않도록 제어하는 작업이 필요하며, 이 작업을 동시성제어(concurrency control)이라고한다.

  • 동시성 제어보다 완화된 방법으로 트랜잭션 고립 수준에 따라 상호간섭을 완화시키는 방법도 있다.

지속성

  • 트랜잭션이 정상적으로 완료 혹은 부분 완료한 데이터는 반드시 데이터베이스에 기록되어야한다.

  • DBMS 복구 시스템은 트랜잭션이 작업한 내용을 수시로 log 데이터베이스에 기록했다가, 문제가 발생하면 로그파일을 이용해서 복구작업을 수행한다. 시스템이 멈추더라도 트랜잭션 수행으로 변경된 내용은 디스크에 기록된다.

  • 트랜잭션 상태도

    • DBMS는 부분완료 상태에서 작업 내용(버퍼 내용)을 데이터베이스에 반영하고

    • 실패상태에서는 작업 내용을 취소한다.

03) 트랜잭션과 DBMS

  • DBMS는 트랜잭션이 ACID를 유지할수있도록 지원한다.

    • 원자성 유지하기 위해

      • 회복(복구) 관리자 프로그램 작동.

      • DB가 변경한 내용을 로그로 기록하고 있다가, 트랜잭션에 문제 발생시 원래 상태로 되돌린다.

    • 일관성 유지 위해

      • 트랜잭션 수행시, 데이터에 변경이 가해질 때 미리 정의해둔 무결성 제약조건을 검사하여 일관성이 깨지는 것을 방지한다.

      • 두개의 트랜잭션이 동시에 수행될 때 트랜잭션간의 간섭으로 일관성이 깨지는 현상은 무결성 제약조건으로 해결 불가능하고, 질서있게 접근할 수 있도록 '동시성 제어(Locking) 알고리즘'을 작동시켜야한다.

    • 고립성 유지 위해

      • 동시성 제어 알고리즘을 작동시켜서, 여러 트랜잭션이 동시에 같은 데이터를 접근할 때 마치 한 트랜잭션씩 순서대로 접근하는 것 처럼 제어한다.

    • 영속성 유지 위해

      • 회복 관리자 프로그램으로 트랜잭션에 문제 발생시 기록해둔 로그를 확인하고 원래 상태로 되돌린다.

02. 동시성 제어

  • 트랜잭션이 동시 수행될 때, 일관성을 헤치지 않도록 트랜잭션의 데이터 접근을 제어하는 DBMS의 기능

  • 두개의 트랜잭션이 동시에 한개의 데이터에 접근할 때 발생할 수 있는 시나리오

    • 상황

      트랜잭션1

      트랜잭션2

      발생문제

      동시접근

      [상황1]

      읽기

      읽기

      문제없음

      허용

      [상황2]

      읽기

      쓰기

      유령데이터 읽기, 반복 불가능 읽기, 오손읽기

      허용 혹은 불가

      [상황3]

      쓰기

      쓰기

      갱신손실 (절대 허용 X)

      허용 불가 (LOCK)사용

01)갱신 손실 (lost update)

  • 한개의 데이터를 동시에 두 트랜잭션이 갱신(쓰기, 쓰기)할 때 발생.

    • 트랜잭션 T1, T2가 있고 계좌 X(1000원보유) 에서 T1은 100원을 인출하고, T2는 100원을 입금하는 작업. 그럼 그 결과는 1000이 되어야하는데,

    • 두개의 트랜잭션이 동시에 실행이 된다면, buffer 영역에서

      T1이 인출해서 X가 900원이 된 것을 disk에 갱신이 하기 전에 T2가 동시에 buffer 영역에서 실행되어 X가 1100원이 됨.

    • 그래서 T1이 작업한 내용을 disk에 입력된 뒤, T2가 내용을 덮어서 결과가 1100이 됨.

    • T1-> T2 혹은 T2-> T1순으로 실행하면 내용이 덮히는건 방지할 수 있지만, 응답속도가 느려짐. 이를 해결하기 위해 '락'을 사용함

02) 락(Lock)

  • 트랜잭션이 데이터를 읽거나 수정할 때, 데이터에 표시하는 잠금 장치이다.

  • 락을 이용하여 사용할 데이터를 잠그면, 다른 트랜젝션에서 잠금이 풀릴 때까지 기다려야한다. (wait)

  • 락의 유형

    • 읽기를 할 때 사용하는 공유락(LS, Shared Lock)

    • 읽고 쓰기를 할 때 사용하는 배타락(LX, Exclusive Lock)

    • 트랜잭션이 LS, LX를 사용하는 규칙

      • 데이터에 락이 걸려있지 않으면 트랜잭션은 데이터에 락을 걸 수 있다.

      • 트랜잭션이 데이터 X를 읽기만 할 경우 LS(X)를 요청하고, 읽거나 쓸 경우 LX(X)를 요청한다.

      • 다른 트랜잭션이 데이터에 LS(X)를 걸어둔 경우, LS(X)의요청은 허용하고 LX(X)는 허용하지 않는다.

      • 다른 트랜잭션이 데이터에 LX(X)를 걸어둔 경우, LS(X)와 LX(X) 모두 허용하지 않는다.

      • 트랜잭션이 락을 허용받지 못하면 대기 상태가 된다.

  • 2단계 락킹

    • 데이터에 락을 걸었다 풀고 다시 거는 중간 과정에 락의 해지 상태가 생기면서, 다른 트랜잭션에게 중간 결과를 보임으로써, 데이터의 일관성이 깨질수 있음. 이를 방지하기 위해 2단계 락킹 기법을 사용.

      • 확장단계: 트랜잭션이 필요한 락을 획득하는 단계. 이 단계에서는 이미 획득한 락을 해제하지 않는다.

      • 수축단계: 트랜잭션이 락을 해제하는 단계로, 새로운 락을 획득하지 않는다.

  • 데드락

    • 2개 이상의 트랜잭션이 각각 자신의 데이터에 대해 락을 획득하고, 상대방 데이터에 대하여 락을 요청하면 무한 대기 상태에 빠질 수 있음.

    • 일반적으로 데드락이 발생하면, 작업 중 하나를 강제로 중지시킨다. 이 때, 중지 시킨 트랜젝션에서 변경한 데이터는 원래 상태로 되돌려 놓는다.

03. Transaction Isolation level (트랜잭션 고립(격리) 수준)

두개의 트랜잭션(T1, T2) 중, T1은 읽기작업을, T2는 쓰기 작업을 한다고 생각해보자. 이 때, 동시성제어에서 봤던 '락'을 거는 방법을 사용해서 wait를 할수도 있겠지만, 동시 진행 정도를 과도하게 막는 것이기도 하다. 그래서 완화된 방법으로 나왔다. Isolation level 의 조정을 통해 동시성을 증가시키면 데이터 무결성문제가 발생할 수 있고, 데이터 무결성을 유지하려하면 동시성이 떨어질 수 있다.

1) Transaction 동시 실행 문제

  • dirty read (uncommitted, 오손읽기)

    • 읽기 작업을 하는 트랜잭션 1이 쓰기 작업을 하는 트랜잭션2 가 작업한 중간 데이터를 읽기 때문에 생기는 문제

    • 작업 중 트랜잭션2가 어떤 이유로 작업을 철회(ROLLBACK) 할 경우, 트랜잭션1은 무효화 된 데이터를 읽게 되어 잘못된 결과를 도출하는데, 이 현상을 dirty read (오손읽기) 또는 uncommitted 라고 한다.

    • 읽기 작업을 하는 동안 해당 데이터에 shared lock이 걸리지 않아 생긴 문제.

  • non-repeatable read (반복 불가능)

    • 트랜잭션1 이 데이터를 읽고, 트랜잭션2 가 데이터를 쓰고(update, 갱신) commit, 트랜젝션1이 다시 한 번 데이터를 읽을 때 생기는 문제

    • 즉, 읽기작업을 다시 한 번 반복할 경우 이전 결과가 반복되지 않는 현상

  • phantom read(유령 읽기)

    • 트랜잭션1 이 데이터를 읽고, 트랜잭션2 가 데이터를 쓰고(insert, 삽입), 트랜잭션1이 다시 한 번 데이터를 읽을 때 생기는 문제

    • 트랜잭션 이 다시한번 데이터를 읽으면, 이전에 없던 데이터가 나타나는 현상

    • 단, MySQL에서는 발생하지 않는다. MySQL의 REPEATABLE READ는 트랜젝션이 처음 데이터를 읽어올 때, SNAPSHOT을 구축해서 자료를 가져오므로, 다른 세션의 자료가 변경되더라도 동일한 결과를 보여준다.

2) Transaction Isolation level 명령어

  • 사용자가 선택해서 트랜잭션을 제어한다.

  • 읽기/쓰기에 대한 트랜잭션 간의 고립수준을 결정

  • SQL 표준에서는 4가지 고립(isolation) 수준을 정의하고 있고, DBMS별로 지원하는 모드, 동작 방식, 결과가 다르다.

  • SQL 표준으로 정리

    • READ UNCOMMITED(Level 0)

      • 고립수준이 가장 낮은 명령어로 자신의 데이터에 아무런 shared lock(공유락) 을 걸지 않는다.

      • 베타락은 갱신 손실 문제 때문에 걸어야함.

      • 다른 트랜잭션에 공유락과 배타락이 걸린 데이터를 대기하지 않고 읽는다. 다른 트랜잭션이 commit하지 않은 데이터도 읽을 수 있기 때문에 이 때 dirty read 할 가능성이 생긴다.

      • SELECT 질의에 NO LOCK 한 것과 같다.

    • READ COMMITED (Level 1)

      • dirty read 를 피하기 위해, 자신의 데이터를 읽는동안 shared lock을 걸지만, 트랜젝션이 끝나기 전에도 해지 가능.

      • 다른 트랜잭션 데이터는 락 호환성 규칙에 따라 진행

    • REPEATABLE READ (Level 2)

      • 자신의 데이터에 shared lock, 베타 lock을 트랜잭션이 종료할 때까지 유재해서, 다른 트랜잭션에 자신의 데이터를 update하지 않도록 한다.

      • 다른 고립화 수준에 비해 동시성이 낮다. 또한, MySQL은 공유락을 걸지 않고, 최초 트랜잭션 SELECT 수행시 SNAPSHOT을 만든 후, 이 SNAPSHOT으로 select를 수행하여 다른 트랜잭션의 변경시에도 동일한 결과를 유지 한다.

    • SERIALIZABLE (Level3)

      • 고립수준이 가장 높고, 실행중인 트랜잭션은 다른 트랜잭션으로부터 완벽하게 분리된다.

      • 데이터 집합에 범위를 지어 잠금 설정을 할 수 있고, 다른 사용자가 데이터 변경시 트랜잭션을 완벽히 분리할 수 있다.

      • 데이터의 동시성이 낮고, SELECT 질의에 베타락을 설정한 것과 동일한 효과를 낸다.

04. 회복

  • 데이터 베이스에 장애 발생시, 데이터베이스를 일관성 있는 상태로 되돌리는 DBMS 기능

  • DB system에서 발생가능 한 장애 유형

    • 시스템 충돌: HW, SW 의 오류로 주기억장치가 손실되어 처리중인 프로그램과 데이터의 일부 혹은 전부가 손실됨.

    • 미디어 장애: 헤드 충돌이나, 읽기 장애로 보조기억장치가 손실

    • 응용 소프트웨어 오류: DB에 접근하는 SW의 논리적인 오류로 트랜잭션 수행 실패

    • 자연재해: 자연재해로 컴퓨터 시스템이 손상

    • 부주의 혹은 의도적인 손상

    • 크게 2가지로 요약: 변경중인 데이터를 가지고 있는 주기억장치 손실 혹은 데이터베이스가 저장된 하드디스크가 손실.

01) 트랜잭션 회복

  • 트랜잭션은 DB 회복 단위이기도 함.

  • 트랜잭션은 데이터의 변경내용을 한순간에 데이터베이스에 모두 저장하는 것이 아님!

  • 일단 변경한 내용(buffer에 있음)을 로그(임시 디스크)에 기록 한 후, 데이터베이스에 반영을 함.

  • DBMS의 회복 관리자는 트랜잭션의 ACID중 원자성(A), 지속성(D) 를 보장하여 장애로부터 DB를 보호한다.

    • 장애 발생 시 로그 내용을 참조해서, 트랜잭션의 변경 내용을 모두 반영하거나 아니면 아예 반영하지 않는 방법으로 원자성을 보장한다.

    • 일단 트랜잭션이 commit 한 내용은 로그를 이용해서 반드시 데이터베이스에 저장한다.

02) 로그파일

  • DBMS는 트랜잭션이 수행중이거나, 수행이 종료된 후 발생하는 데이터베이스 손실을 방지하기 위해

    트랜잭션의 데이터베이스 기록을 추적하는 로그파일을 사용한다.

  • 로그 파일은 트랜잭션이 반영한 모든 데이터의 변경사항을 데이터베이스에 기록하기 전에 미리 기록해두는 별도의 데이터 베이스.

  • 안전한 하드디스크에 저장되며, 전원과 관계없이 기록이 남아있음.

  • 로그 파일에 저장된 로그 구조

    • <트랜잭션 번호, 로그타입, 데이터 항목 이름, 수정 전 값, 수정 후 값>

      • 로그타입: 트랜잭션의 연산 타입 (ex, start, insert, delete, update, abort, commit, ...)

      • 수정 전 값: 데이터 변경 전 값

      • 수정 후 값: 연산 결과로 변경된 값

03) 로그파일을 이용한 회복

  • 시스템 운영 중 장애가 발생하여 시스템이 다시 가동 되었을 때, DBMS는 먼저 로그파일을 살핀다.

  • DBMS는 트랜잭션이 종료되었는지, 중단되었는지 여부를 판단하고

    • 종료된 트랜잭션은 종료를 확정하기 위해 재실행(REDO)를 진행

    • 중단된 트랜잭션은 없던 일로 되돌리기 위해 취소(UNDO)를 진행

  • 재실행(REDO)

    • 장애 발생 후, 시스템을 다시 가동했을 때, 로그 파일에 트랜잭션의 시작(START) 과, 종료(commit) 이 있는 경우.

    • commit 연산이 로그에 있다 => 트랜잭션이 모두 완료됨.

    • 변경 내용이 기록 되지 않았을 가능 성이 있으므로, 로그를 보면서 트랜잭션이 변경한 내용을 DB에 다시 기록하는 과정이 필요.

  • 취소(UNDO)

    • 장애 발생 후, 시스템을 다시 가동했을 때, 로그 파일에 트랜잭션의 시작(START) 만 있고, 종료(commit)가 없는 경우.

    • commit 연산이 로그에 없다 => 트랜잭션이 완료되지 않음.

    • 트랜잭션이 한 일을 모두 취소해야함.

    • 완료하지 못했지만, 버퍼의 변경 내용이 DB에 기록되었을 가능성이 있으므로, 트랜잭션이 변경한 내용을 로그를 보며 원상복구 해야한다.

  • 위 두 작업은 트랜잭션 로그 DB에 기록한 모든 값에 대하여(변경전 값, 변경후 값) 중 어느 하나를 DB에 맞는 값으로 수정하는 작업

  • 즉시 갱신(immediate update)

    • 트랜잭션의 부분완료 전에라도, 변경한 내용 일부가 데이터베이스에 기록 될 수 있음.

  • 지연 갱신 (deferred update)

    • 트랜잭션이 반드시 부분완료된 후, 변경 내용을 DB에 기록

    • 부분 완료 이전에는 갱신 내용이 아직 실제 DB에는 반영되지 않은 상태.

    • 데이터베이스에 반영하는 작업은 지연되지만, 장애 발생시 로그에 START만 나타나는 트랜잭션은 취소(UNDO) 할 필요가 없음.

04) 체크포인트를 이용한 회복

  • 로그를 이용한 회복은 시스템 장애 발생시, 어느 시점까지 돌아가야하는지 알 수 없다.

  • 따라서 트랜잭션이 많은 경우, 시간이 상당히 오래 걸린다.

  • 많은 양의 로그를 검색하고, 갱신하는 시간을 줄이기 위해 몇 십 분 단위DB와 트랜잭션 로그 파일을 동기화 한 후, 동기화한 시점을 로그파일에 기록해두는 방법 혹은 그 시점을 체크포인트라고 한다.

  • 체크 포인트 시점에서 하는 작업

    • 주기억 장치의 로그 레코드를 모두 하드 디스크의 로그 파일에 저장

    • 즉시 갱신의 경우, 버퍼에 있는 변경된 내용을 하드 디스크의 DB에 저장.

    • 체크포인트를 로그에 기록

  • 트랜잭션의 로그 기록에 따라 회복하는 방법

    • 체크포인트 이전에 Commit 기록이 있는 경우: 아무 작업이 필요 없다.

    • 체크포인트 이후에 Commit 기록이 있는 경우: REDO(T)를 진행한다.

    • 체크포인트 이후에 Commit 기록이 없는 경우: 즉시 갱신 방법 사용시 UNDO(T) 진행, 지연 갱신 시 아무것도 할 필요 X.

[그림 참조]

[전체 내용]

MySQL로 배우는 데이터 베이스 개론과 실습 책 참조

[Transaction Isolation level 참조]

https://doooyeon.github.io/2018/09/29/transaction-isolation-level.html

Last updated

Was this helpful?