본문 바로가기

Tech/데이터베이스

[데이터베이스] 트랜잭션(Transaction)

트랜잭션(Transaction)은 데이터베이스의 상태를 변환시키는 하나의 논리적 기능을 수행하기 위한 작업의 단위 또는 한꺼번에 모두 수행되어야 할 일련의 연산

트랜잭션의 성질(ACID)

Atomicity(원자성)

  • 트랜잭션의 연산은 데이터베이스에 모두 반영되든지 아니면 전혀 반영되지 않아야 한다. (ALL-OR-NOTHING. 더 이상 쪼갤 수 없는 상태인 원자의 성질을 가졌다는 의미에서 원자성이라고 함)
  • 트랜잭션 내의 모든 명령은 반드시 수행되어야 하며, 어느 하나라도 오류가 발생하면 트랜잭션 전부가 취소되어야 한다.

Consistency(일관성)

  • 트랜잭션의 작업 처리 결과가 항상 일관성이 있어야 한다

Isolation(고립성)

  • 둘 이상의 트랜잭션이 동시에 병행 실행되는 경우 어느 하나의 트랜잭션 실행 중에 다른 트랜잭션의 연산이 끼어들 수 없다.
  • 수행 중인 트랜잭션은 완전히 완료될 때까지 다른 트랜잭션에서 수행 결과를 참조할 수 없다.

Duarability(지속성, 영구성)

  • 성공적으로 완료된 트랜잭션의 결과는 시스템이 고장나더라도 영구적으로 반영되어야 한다.

 

트랜잭션의 연산

Commit

  • 모든 작업들을 정상적으로 처리하겠다고 확정하는 명령어로 처리과정을 DB에 영구 저장하는 것
  • commit을 수행하면 이전 데이터가 완전히 업데이트되고 트랜잭션 과정을 종료하게 된다.

Rollback

  • 작업 중에 문제가 발생되어 트랜잭션의 처리과정에서 발생한 변경사항을 취소하는 명령어
  • 트랜잭션이 시작되기 이전의 상태, 즉 마지막 commit을 완료한 시점으로 다시 돌아간다.

Savepoint

  • 일반적으로 Rollback이 발생하면 트랜잭션 작업 전체가 취소된다. 하지만 Savepoint를 지정함으로써 사용자가 트랜잭션 중간 단계에서부터 취소되도록 할 수 있다. (우리가 문서 작업이나 ppt 만들 때 중간중간 저장해둬서 컴터가 꺼지더라도 그 부분까지는 저장될 수 있도록 하는 것과 같은 맥락)

 

트랜잭션의 상태

  1. 활동(Active) : 트랜잭션이 실행 중에 있는 상태, 연산들이 정상적으로 실행 중인 상태
  2. 실패(Failed) : 트랜잭션 실행에 오류가 발생하여 중단된 상태
  3. 철회(Aborted) : 트랜잭션이 비정상적으로 종료되어 Rollback 연산을 수행한 상태
  4. 부분 완료(Partially Committed) : Commit 연산이 실행되기 직전의 상태로 아직 작성한 것들을 저장하지 않은 상태
  5. 완료(Committed) : 트랜잭션이 성공적으로 종료되어 Commit 연산을 실행한 후의 상태

 

트랙잭션 격리 수준(isolation level)

 

[데이터베이스] 트랜잭션 격리수준

https://joont92.github.io/db/%ED%8A%B8%EB%9E%9C%EC%9E%AD%EC%85%98-%EA%B2%A9%EB%A6%AC-%EC%88%98%EC%A4%80-isolation-level/https://mozi.tistory

velog.io

트랜잭션 격리수준(isolation level)이란 동시에 여러 트랜잭션이 처리될 때, 트랜잭션끼리 얼마나 서로 고립되어 있는지를 나타내는 것. 간단하게 말해 특정 트랜잭션이 다른 트랜잭션에 변경한 데이터를 볼 수 있도록 허용할지 말지를 결정하는 것.

트랜잭션 격리가 왜 필요한가?

→ 트랜잭션 수준 읽기 일관성 (Transaction-Level Read Consistency)을 지키기 위해. (동시성 제어 문제 해결을 위함)

  • 트랜잭션 수준 읽기 일관성?
    • 트랜잭션이 시작된 시점으로부터 일관성 있게 데이터를 읽어 들이는 것
    • 하나의 트랜잭션이 진행되는 동안 다른 트랜잭션에의해 변경사항이 발생하더라도 이를 무시하고 계속 일관성 있는 데이터를 보여줌

4단계로 구성되어 있으며, 수준이 높아질수록 트랜잭션간 고립 정도가 높아지는 대신 성능이 저하된다.

[level 0] Read Uncommited

  • 트랜잭션에서 처리 중인, 아직 커밋되지 않은 데이터를 다른 트랜잭션이 읽는 것을 허용한다.
  • Dirty Read 문제 발생

[level 1] Read Commited

  • 커밋된 데이터만 읽는 격리 수준
  • RDB에서 대부분 기본적으로 사용되고 있는 격리 수준으로 실제 테이블 값을 가져오는 것이 아니라 Undo 영역에 백업된 레코드에서 값을 가져온다.
  • Non-Repeatable Read 문제 발생

[level 2] Repeatable Commited

  • 데이터 조회시 항상 동일한 데이터 응답을 보장하는 고립 수준
  • MySQL에서는 트랜잭션마다 트랜잭션 ID를 부여하여 트랜잭션 ID보다 작은 트랜잭션 번호에서 변경한 것만 읽게 된다.
  • 변경되기 전 레코드는 Undo 공간에 백업해두고 실제 레코드 값을 변경한다
  • Update 부정합 문제 발생
    • 트랜잭션 A에서 바라보고 있는 데이터가 트랜잭션 B에 의해서 수정 후 커밋 되었을 때
    • repeateable read 정합성에 의해 동일한 데이터가 여전히 조회되지만 업데이트시 문제 발생
    • 업데이트를 위해 해당 row를 lock하기 위해 데이터를 찾지만 이미 변경되어 없는 데이터이기 때문
    • 조회가 가능한 이유는 실제 레코드 값이 아닌 undo에 있는 값을 가져오는 것이기 때문
  • Phantom Read 문제 발생
  • Undo에 백업된 레코드가 많아져서 멀티 버전을 관리해야하는 단점이 있다.

[level 3] Serializable

  • 트랜잭션이 완료될 때까지 SELECT 문장이 사용되는 모든 데이터에 Shared Lock이 걸리는 격리 수준
  • 가장 엄격한 격리 수준으로 완벽한 읽기 일관성 모드를 제공함
  • 다른 사용자는 트랜잭션 영역에 해당되는 데이터에 대한 수정 및 입력 불가능
  • 성능 측면에서는 동시 처리 성능이 가장 낮음

낮은 단계의 트랜잭션 고립화 수준을 사용할 때 발생하는 현상

Dirty Read

  • 변경 후 아직 Commit 되지 않은 값 읽고, Rollback 후의 값을 다시 읽어 최종 결과 값이 상이한 현상

Non-Repeatable Read

  • 한 트랜잭션 내에서 같은 쿼리를 두번 수행할 때, 다른 트랜잭션 작업에 의해 두 쿼리가 상이하네 나타나는 비 일관성이 발생하는 현상
  • 하나의 트랜잭션 내에서 동일한 SELECT를 수행했을 경우 항상 같은 결과를 반환해야하는 REPEATABLE READ 정합성에 어긋나는 것

Phantom Read

  • 하나의 트랜잭션에서 같은 쿼리를 두 번 실행했을 경우, 첫 번째 쿼리에서 없던 유령 레코드가 두 번째 쿼리에서 나타나는 현상
  • Insert에 대해서만 발생하는 문제 → 쓰기 잠금(write lock)을 걸어야 함

 

트랜잭션 전파

트랜잭션 전파란 트랜잭션의 경계에서 이미 진행 중인 트랜잭션이 있을 때 또는 없을 때 어떻게 동작할 것인가를 결정하는 방식을 의미

REQUIRED

  • 이미 진행 중인 트랜잭션이 없으면 새로 시작
  • 이미 진행 중인 트랜잭션이 있으면 새로 시작하지 않고 기존 트랜잭션에 참여

SUPPORTS

  • 이미 진행 중인 트랜잭션이 있다면 해당 트랜잭션에 합류.
  • 이미 진행 중인 트랜잭션이 없다면 트랜잭션 없이 진행

MANDATORY

  • 이미 진행 중인 트랜잭션이 있으면 해당 트랜잭션에 합류(==REQUIRED)
  • 진행 중인 트랜잭션이 없다면 예외를 발생
  • 독립적인 트랜잭션을 생성하면 안되는 경우 사용

REQUIRES_NEW

  • 항상 새로운 트랜잭션을 시작
  • 이미 진행 중인 트랜잭션이 있으면 기존의 트랜잭션을 대기 상태로 두고 자신의 트랜잭션을 실행함
  • 독립적인 트랜잭션이 보장돼야 하는 코드에 적용

NOT_SUPPORTED

  • 진행 중인 트랜잭션이 있으면 이를 보류시키고, 트랜잭션을 사용하지 않도록 함

NESTED

  • 이미 실행 중인 트랜잭션이 존재한다면 중첩 트랜잭션을 만든다.
  • 중첩 트랜잭션이란
    • 트랜잭션 안에 다시 트랜잭션을 만드는 것
    • 부모 트랜잭션의 커밋/롤백에는 영향을 받지만, 자신은 부모 트랜잭션에게 영향을 주지 않음
  • 부모 트랜잭션이 존재하지 않으면 독립적으로 트랜잭션 생성

NEVER

  • 트랜잭션을 사용하지 않도록 강제
  • NOT_SUPPORTED 는 트랜잭션을 무시하고 보류하는 반면, NEVER는 트랜잭션이 존재하면 예외 발생

 

 

[참고]

반응형