트랜잭션(Transaction)은 데이터베이스의 상태를 변환시키는 하나의 논리적 기능을 수행하기 위한 작업의 단위 또는 한꺼번에 모두 수행되어야 할 일련의 연산
트랜잭션의 성질(ACID)
Atomicity(원자성)
- 트랜잭션의 연산은 데이터베이스에 모두 반영되든지 아니면 전혀 반영되지 않아야 한다. (ALL-OR-NOTHING. 더 이상 쪼갤 수 없는 상태인 원자의 성질을 가졌다는 의미에서 원자성이라고 함)
- 트랜잭션 내의 모든 명령은 반드시 수행되어야 하며, 어느 하나라도 오류가 발생하면 트랜잭션 전부가 취소되어야 한다.
Consistency(일관성)
- 트랜잭션의 작업 처리 결과가 항상 일관성이 있어야 한다
Isolation(고립성)
- 둘 이상의 트랜잭션이 동시에 병행 실행되는 경우 어느 하나의 트랜잭션 실행 중에 다른 트랜잭션의 연산이 끼어들 수 없다.
- 수행 중인 트랜잭션은 완전히 완료될 때까지 다른 트랜잭션에서 수행 결과를 참조할 수 없다.
Duarability(지속성, 영구성)
- 성공적으로 완료된 트랜잭션의 결과는 시스템이 고장나더라도 영구적으로 반영되어야 한다.
트랜잭션의 연산
Commit
- 모든 작업들을 정상적으로 처리하겠다고 확정하는 명령어로 처리과정을 DB에 영구 저장하는 것
- commit을 수행하면 이전 데이터가 완전히 업데이트되고 트랜잭션 과정을 종료하게 된다.
Rollback
- 작업 중에 문제가 발생되어 트랜잭션의 처리과정에서 발생한 변경사항을 취소하는 명령어
- 트랜잭션이 시작되기 이전의 상태, 즉 마지막 commit을 완료한 시점으로 다시 돌아간다.
Savepoint
- 일반적으로 Rollback이 발생하면 트랜잭션 작업 전체가 취소된다. 하지만 Savepoint를 지정함으로써 사용자가 트랜잭션 중간 단계에서부터 취소되도록 할 수 있다. (우리가 문서 작업이나 ppt 만들 때 중간중간 저장해둬서 컴터가 꺼지더라도 그 부분까지는 저장될 수 있도록 하는 것과 같은 맥락)
트랜잭션의 상태
- 활동(Active) : 트랜잭션이 실행 중에 있는 상태, 연산들이 정상적으로 실행 중인 상태
- 실패(Failed) : 트랜잭션 실행에 오류가 발생하여 중단된 상태
- 철회(Aborted) : 트랜잭션이 비정상적으로 종료되어 Rollback 연산을 수행한 상태
- 부분 완료(Partially Committed) : Commit 연산이 실행되기 직전의 상태로 아직 작성한 것들을 저장하지 않은 상태
- 완료(Committed) : 트랜잭션이 성공적으로 종료되어 Commit 연산을 실행한 후의 상태
트랙잭션 격리 수준(isolation level)
트랜잭션 격리수준(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는 트랜잭션이 존재하면 예외 발생
[참고]
'Tech > 데이터베이스' 카테고리의 다른 글
[개발 한 스푼] 데이터 사전(data dictionary)에 대해서 설명해주세요. (2023.01.12) (0) | 2023.01.13 |
---|---|
[Database] Redis 찍먹 (0) | 2022.02.18 |
[데이터베이스] 인덱스(Index) (0) | 2022.02.08 |
[데이터베이스] 정규화(Normalization)와 역정규화(Denormalization) (0) | 2020.08.31 |