Study

[Database] Transaction, Lock

voider 2021. 5. 25. 09:56

Transaction

트랜잭션은 DBMS에서 데이터를 다루는 논리적인 작업 단위다. 트랜잭션은 전부 수행되거나, 전부 수행되지 말아야 한다.(All or Nothing)

트랜잭션의 동작 원리

  1. A계좌의 값을 데이터베이스에서 메모리 버퍼로 읽어온다.
  2. B계좌의 값을 데이터베이스에서 메모리 버퍼로 읽어온다.
  3. A계좌에서 10000원을 인출한 값을 저장.
  4. B계좌에서 10000원을 입금한 값을 저장.
  5. A계좌의 값을 메모리 버퍼에서 데이터베이스에 기록
  6. B계좌의 값을 메모리 버퍼에서 데이터베이스에 기록

이런 작업이 있다고 했을 때, 트랜잭션의 수행 과정은 두 가지 방법으로 나눌 수 있다.
이 두 가지 방법은 커밋이 어느 위치에 들어가느냐에 따라 달라진다.
A. 4번 작업을 마치고 커밋한다.
B. 6번 작업을 마치고 커밋한다.

DBMS는 사용자에게 빠르게 응답하기 위해 방법 A를 선택한다.

커밋Commit은 트랜잭션의 수행이 완료되었다는 것을 트랜잭션 매니저에게 알리는 연산이다.

트랜잭션의 ACID 성질
트랜잭션은 ACID라고 하는 원자성, 일관성, 고립성, 지속성을 보장해야 한다.

  • 원자성Atomicity: 트랜잭션에 포함된 작업은 전부 수행되거나, 전부 수행되지 않는다.
  • 일관성Consistency: 트랜잭션을 수행하기 전이나 후에 데이터베이스는 일관된 상태를 유지한다.
  • 고립성Isolation: 수행 중인 트랜잭션에 다른 트랜잭션이 끼어들어 변경 중인 데이터 값을 훼손하지 않는다.
  • 지속성Durability: 수행을 성공적으로 완료한 트랜잭션은 변경한 데이터를 영구히 저장한다.

동시성 제어Currency Control

다중 사용자 환경에서 둘 이상의 트랜잭션이 동시에 수행될 때, 일관성을 해치지 않도록 트랜잭션의 데이터 접근 제어

트랜잭션이 어떤 일은 동시에 수행할 경우 상황에 따라 충돌이 발생할 수 있다.

동시성 제어가 없을 경우 발생할 수 있는 문제

  • Lost Update: 하나의 트랜잭션이 update한 내용을 다른 트랜잭션이 다시 update해서 갱신이 무효화 되는 경우
  • Dirty read: 완료되지 않은 트랜잭션이 갱신한 데이터를 읽는 경우
  • Non-Repeatable Read: 한 트랜잭션 안에서 동일한 데이터를 두 번 읽을 때 서로 다른 값을 읽는 것
  • Phantom Read: 트랜잭션1이 데이터를 읽고 트랜잭션2가 데이터를 쓰고 트랜잭션1이 다시 데이터를 읽을 때 없던 데이터가 생기는 문제

Transaction Schedule

  • Serial Schedule: 트랜잭션이 실행되어야 다음 트랜잭션을 실행할 수 있다.
  • Non-serial Schedule: 트랜잭션을 병행 수행한다.
  • Serializable Schedule: 서로 영향을 주지 않는 직렬 스케줄을 비직렬으로 수행한다.

트랜잭션 스케쥴이란 연산들의 실행 순서를 말한다.

Lock

  • Locking기법: 트랜잭션이 동일한 데이터 항목에 대해 임의적인 병행 접근을 못하도록 막는다.
  • 트랜잭션 T가 항목 X에 대해 Read(X) or Write(X)연산을 수행하려면 반드시 lock(X)연산을 해야 한다.
  • 트랜잭션 T가 실행한 lock(X)에 대해 해당 트랜잭션이 종료되기 전에 반드시 unlock(X)연산을 해야 한다.
  • 트랜잭션 T는 다른 트랜잭션에 의해 이미 lock이 걸려 있는 X에 대해 다시 lock(X)를 할 수 없다.
  • 트랜잭션 T가 lock을 걸지 않았다면 unlock(X)를 수행할 수 없다.

Lock은 말하자면 동시성을 제어하는 도구다.

  • 공유 락(LS, Shared Lock)
    트랜잭션 T가 항목 X에 대해 Shared Lock을 설정하면 해당 데이터 항목을 읽을 수 있지만 기록할 수는 없다.
    또한 공유 락은 서로 영향을 주지 않으므로 Lock을 동시에 설정할 수 있다.
  • 배타 락(LX, Exclusive Lock)
    배타 락을 설정할 경우 읽기/쓰기가 모두 가능하다. 공유 락과는 다르게 다른 트랜잭션에 영향을 끼칠 수 있으므로
    점유하고 있는 항목에 대해 다른 트랜잭션이 접근할 수 없다.

exclusive lock으로 특정 row를 점유하면, 다른 트랜잭션은 그 row에 대해 어떤 locking도 할 수 없다.
하지만 T1이 exclusive lock으로 점유한 특정 row에 대해 다른 트랜잭션에서 단순 select는 가능하다. 또한 join상태에서 lock을 걸면 join한 테이블의 row까지 전파된다.

Deadlock(교착 상태)
트랜잭션A가 데이터 x에 락을 걸고 트랜잭션B는 데이터 y에 락을 건 상태에서, B가 x에 락을 걸고 A가 y에 락을 걸면 A와 B는 각자의 락을 유지하면서 무한루프에 빠질 수 있다.

트랜잭션 격리 수준

READ UNCOMMITTED

  • 가장 낮은 격리 수준
  • 갱신하려는 데이터에 대해 독점 lock을 걸고 트랜잭션 끝날 때까지 보유
  • DIRTY READ, NON-REPEATABLE READ, PHANTOM READ 발생 가능

READ COMMITED

  • 트랜잭션 내 질의들이 읽으려는 데이터에 대해 공유 락을 걸고 읽기가 끝나면 락을 해제한다.
  • DIRTY READ를 허용하지 않는다. 커밋한 데이터만 읽을 수 있다.
  • NON-REPEATABLE READ는 발생할 수 있다.

REPEATABLE READ

  • 질의에서 검색되는 데이터에 대해 공유 락을 걸고 트랜잭션이 끝날 때까지 보유
  • NON-REPEATABLE READ를 허용하지 않는다. 반복 조회해도 같은 결과가 나온다.
  • PHANTOM READ를 허용한다.

SERIALIZABLE

  • 가장 엄격한 격리 수준
  • PHANTOM READ가 발생하지 않는다.
  • 질의에서 검색되는 튜플 뿐 아니라, 인덱스에 대해서도 공유 락을 걸고 트랜잭션이 끝날 때까지 보유
  • 일관성을 높이지만 동시성 저하

참고 자료: https://mangkyu.tistory.com/30?category=761304