트랜잭션
- 데이터베이스의 상태를 변화시키기 위해 수행하는 작업 단위
- 트랜잭션의 연산
- commit
- 하나의 트랜잭션이 성공적으로 종료된 후, 갱신 연산이 완료되었다고 관리자에게 알려주고 최종적으로 데이터베이스에 반영하는 연산
- rollback
- 트랜잭션이 비정상적으로 종료되어 DB의 일관성을 잃었을 때, 지금까지의 연산의 결과를 취소하고 트랜잭션 수행 이전의 상태로 돌아가는 연산
- 논리적인 작업 set을 모두 완벽하게 처리하거나(commit), 또는 처리하지 못할 경우 원 상태로 복구해서 작업의 일부만 적용되는 현상이 발생하지 않게 만들어 주는(rollback) 기능
예시) 사용자 A가 사용자 B에게 만원을 송금한다.
* 이때 DB 작업
- 1. 사용자 A의 계좌에서 만원을 차감한다 : UPDATE 문을 사용해 사용자 A의 잔고를 변경
- 2. 사용자 B의 계좌에 만원을 추가한다 : UPDATE 문을 사용해 사용자 B의 잔고를 변경
현재 작업 단위 : 출금 UPDATE문 + 입금 UPDATE문
→ 이를 통틀어 하나의 트랜잭션이라고 한다.
- 위 두 쿼리문 모두 성공적으로 완료되어야만 "하나의 작업(트랜잭션)"이 완료되는 것이다. `Commit`
- 작업 단위에 속하는 쿼리 중 하나라도 실패하면 모든 쿼리문을 취소하고 이전 상태로 돌려놓아야한다. `Rollback`
트랜잭션 특징(ACID)
- 원자성(Atomicity)
- 트랜잭션이 DB에 모두 반영되거나, 혹은 전혀 반영되지 않아야 한다.
- 일관성(Consistency)
- 트랜잭션의 작업 처리 결과는 항상 일관성이 있어야 한다.
cascade
- 독립성(Isolation)
- 둘 이상의 트랜잭션이 동시에 병행 실행되고 있을 때, 어떤 트랜잭션도 다른 트랜잭션 연산에 끼어들 수 없다.
트랜잭션 격리 수준
- 지속성(Durability)
- 트랜잭션이 성공적으로 반영되면, 결과는 영구적으로 반영되어야 한다.
Undo, Redo

서버에 장애가 발생하거나 인스턴스가 비정상 종료했을 때,
Redo
와 Undo
를 사용해 데이터를 복구하고 rollback
을 진행한다.- Undo
- 최신 데이터를 오래된 데이터로 만들기 위해 존재함
- 트랜잭션을 이전 상태로 되돌리는것을 의미
- 읽기 일관성을 지키기 위해 Undo를 사용한다.
- 멀티 유저의 읽기 일관성 보호
- 데이터가 변경되면 Undo의 세그먼트가 생성되며, Undo 세그먼트는 트랜잭션과 일대일로 대응한다.
- Redo
- 오래된 데이터를 최신 데이터로 만들기 위해 존재
- 이전 상태로 되돌아간 후, 실패가 발생하기 전까지의 과정을 그대로 따라가는걸 의미한다.
트랜잭션의 교착상태
- 복수의 트랜잭션을 사용하면 교착상태가 일어날 수 있다.
- 대표적으로, MVCC(다중 버전 동시성 제어)가 있다.
- 동시성 제어
- DBMS에서 다수의 사용자 사이에서 동시에 작용하는 다중 트랜잭션의 상호간섭 작용에서 DB를 보호하는 것
LOCK
과 같은 기능을 통해 동시성 제어를 한다. 하지만Locking
메커니즘에는 문제점이 있다.- 읽기 작업과 쓰기 작업이 서로 방해를 일으키기 때문에 동시성 저하 발생
- MVCC(다중 버전 동시성 제어, Multi-Version Concurrency Control)
- 동시 접근을 허용하는 데이터베이스에서 동시성을 제어하기 위해 사용하는 방법 중 하나이다.
- MVCC에서는, 변경이 진행 중인 레코들을 만나더라도 대기하지 않는다.
- 데이터를 변경할 때마다, 그 변경사항을
UNDO
영역에 저장한다. - 데이터를 읽다가 쿼리 또는 트랜잭션 시작 시점 이후에 변경된 값을 발견하면,
UNDO
영역에 저장된 정보를 이용해 쿼리 시점의 일관성 있는 버전을 생성하고 읽는다. - 따라서 하나의 데이터에 여러 버전의 데이터가 존재하게 된다.
- 장점
- 일반적인 RDBMS보다 매우 빠르게 작동
- 단점
- 사용하지 않는 데이터가 계속 쌓이므로, 데이터를 정리하는 시스템이 필요
트랜잭션 격리 수준
- 트랜잭션에서 일관성 없는 데이터를 허용하도록 하는 수준
- DB는 ACID 특징과 같이 트랜잭션이 독립적인 수행을 하도록 한다.
- 따라서
Locking
을 통해 트랜잭선이 DB를 다루는 동안 다른 트랜잭션이 관여하지 못하게 막아야 한다. - 독립성을 챙기며 지나치게 성능 저하가 일어나지 않도록, 효율적인
Locking
방법이 필요함
- 격리 수준의 종류
- Read Uncommitted (level 0)
- SELECT 문장이 수행되는 동안 해당 데이터에 Shared Lock이 걸리지 않는 계층
- 데이터의 일관성을 유지하는것이 불가능함
사용자1이 A라는 데이터를 B라는 데이터로 변경하는 동안 사용자2는 아직 완료되지 않은(Uncommitted) 트랜잭션이지만 데이터B를 읽을 수 있다
- SELECT 문장이 실행되는 동안 해당 데이터에 Shared Lock이 걸리는 계층
- Commit이 일어나는 트랜잭션만 조회 가능, 현재 대부분의 SQL 서버가 defulat로 사용
사용자1이 A라는 데이터를 B라는 데이터로 변경하는 동안 사용자2는 해당 데이터에 접근이 불가능함
Undo
공간에 백업해두고 실제 레코드 값을 변경한다. → MVCC 방식 사용- 백업된 데이터는 불필요하다고 판단하는 시점에 주기적으로 삭제한다.
Undo
에 백업된 레코드가 많아지면 MySQL 서버의 처리 성능이 떨어질 수 있다.- 트랜잭션마다 트랜잭션 ID를 부여하여 트랜잭션 ID보다 작은 트랜잭션 번호에서 변경한 것만 읽게 된다
- MYSQL에서 사용하는 레벨
- 트랜잭션들이 동시에 일어나지 않고, 순차적으로 실행되는 것처럼 동작
- 거의 사용되지 않는다
낙관적 락과 비관적 락
- 데이터 수정 시점에 충돌이 발생하는지를 확인하며, 충돌이 발생하면 트랜잭션을 실패시키고 다시 시도하도록 한다.
- 데이터에 버전 번호나 타임스탬프를 부여하여, 커밋 시점에 현재 데이터의 버전과 수정하려는 데이터의 버전을 비교
- DB에서 제공해주는 특징을 사용하는 것이 아닌, Application Level에서 잡아주는 Lock이다.
- 개발자가 직접 롤백 처리를 해줘야 한다.
- 사용 예시(JPA)
→ 다중 사용자 환경에서 데이터 경합이 드물다고 가정하고, 데이터 액세스 시 락을 걸지 않고 변경을 시도하는 동시성 제어 메커니즘
→ 만약 버전이 일치하면 변경 사항을 커밋하고, 버전을 증가시킨다.
→ 버전이 불일치하면 다른 트랜잭션에 의해 데이터가 변경된 것이므로, 현재 트랜잭션을 롤백하고 재시도하거나 오류를 반환한다.
entityManager.find(MyEntity.class, id, LockModeType.OPTIMISTIC);
- 경량화: 락을 사용하지 않으므로 오버헤드가 적다
- 낮은 경합 환경에 적합: 데이터 충돌이 드물게 발생하는 환경에서 효율적
- 낮은 대기 시간: 락을 기다릴 필요가 없어 응답 속도가 빠르다
- 재시도 필요성: 충돌이 발생하면 트랜잭션을 재시도해야함
- 데이터 경합이 빈번하게 발생할 것으로 가정하고, 데이터에 접근하는 동안 다른 트랜잭션이 해당 데이터에 접근하지 못하도록 락을 거는 동시성 제어 메커니즘
- 트랜잭션이 시작될 때 Shared Lock(공유락, 트랜잭션 읽기를 할 때 사용하는 락) 또는 Exclusive Lock(배타락, 데이터를 변경할 때 사용하는 락)을 걸고 시작하는 방법
- 먼저 Exclusive Lock을 가져간 트랜잭션이 Commit을 완료해야만, 다른 트랜잭션이 업데이트를 진행할 수 있다.
- Repeatable Read 또는 Serializable 정도의 격리성 수준 제공
- 특징
- 높은 신뢰성: 데이터 충돌을 사전에 방지하여 데이터 무결성을 보장
- 높은 경합 환경에 적합: 다수의 트랜잭션이 동시에 동일한 데이터를 수정하는 환경에서 효과적
- 락으로 인한 대기 발생: 락으로 인해 다른 트랜잭션이 대기해야 하므로 응답 시간이 증가할 수 있음
- 데드락 위험성: 여러 트랜잭션이 서로 락을 기다리며 교착 상태에 빠질 수 있다
- 기본적으로 성능 자체는 낙관적 락이 더 좋음(트랜잭션이 필요하지 않기 때문)
- 하지만 충돌이 많이 일어나는 경우, 낙관적 락은 Version Update 처리와 수동 에러 처리로 인한 오버헤드가 더 심해져 비관적 락이 더 좋은 선택지가 될 수도 있다.
개념 | 설명 | 특징 | 사용 사례 |
낙관적 락 | 데이터 수정 시점에 충돌이 발생하는지를 확인하며, 충돌이 발생하면 트랜잭션을 실패시키고 다시 시도하도록 한다 | - 락 오버헤드가 없음
- 충돌 시 재시도 필요
- 낮은 경합 환경에 적합 | - 읽기 위주의 웹 애플리케이션 - 분산 시스템 |
비관적 락 | 데이터에 접근하는 동안 다른 트랜잭션이 해당 데이터에 접근하지 못하도록 공유락/배타락을 거는 동시성 제어 메커니즘 | - 높은 신뢰성
- 락으로 인한 대기 발생
- 높은 경합 환경에 적합 | - 금융 거래 시스템
- 재고 관리 시스템 |
공유락, 배타락, 레코드락
- 공유락(Shared Lock)
- 트랜잭션이 데이터를 읽는 동안 다른 트랜잭션도 해당 데이터를 읽을 수 있지만, 쓰기는 할 수 없도록 제한하는 락의 한 종류
- 트랜잭션이 데이터를 읽으려고 할 때 공유락을 건다.
- 다수의 읽기 작업을 병렬로 처리하여 성능을 높일 수 있고, 데이터의 일관성을 유지함
- 쓰기 지연이 발생할 수 있고, Lock 오버헤드가 일어날 수 있다.
- 사용 예시(JPA)
entityManager.find(MyEntity.class, id, LockModeType.PESSIMISTIC_READ);
- 배타락(Exclusive Lock)
- 트랜잭션이 데이터를 수정하는 동안 다른 트랜잭션이 해당 데이터에 대한 읽기나 쓰기를 모두 할 수 없도록 제한
- 트랜잭션이 데이터를 수정하려고 할 때 배타락을 건다.
- 데이터 수정 시 높은 수준의 일관성과 무결성을 보장하고, 충돌을 사전에 방지해 오류를 최소화한다.
- Lock으로 인한 성능 저하가 발생할 수 있고, 데드락이 발생할 수 있다.
- 사용 예시(JPA)
entityManager.find(MyEntity.class, id, LockModeType.PESSIMISTIC_WRITE);
- 레코드 락(Record Lock)
- 데이터베이스에서 특정 행(row) 또는 레코드에 대해 적용되는 락으로, 해당 레코드에 대한 동시 접근을 제어하기 위해 사용
- 보다 세밀한 수준의 Lock 설정에 사용된다.
- 세밀한 동시성 제어: 레코드 수준에서 락을 관리하여 동시성을 높이고 경합을 줄일 수 있지만, 복잡성이 증가한다.
개념 | 설명 | 특징 | 사용 사례 |
공유 락 | 데이터를 읽는 동안 다른 트랜잭션의 읽기는 허용하고 쓰기는 제한하는 락 | - 동시 읽기 허용
- 쓰기 충돌 방지
- 읽기 작업이 빈번한 환경에 적합 | - 보고서 생성 시스템
- 뉴스 사이트 |
배타적 락 | 데이터를 수정하는 동안 다른 트랜잭션의 모든 접근을 제한하는 락 | - 강력한 일관성 보장
- 높은 경합 가능성
- 중요한 데이터 수정 작업에 적합 | - 금융 거래
- 주문 처리 시스템 |
레코드 락 | 특정 레코드에 대해 적용되는 락으로, 세밀한 수준의 동시성 제어를 가능하게 함 | - 동시성 향상 - 복잡성 증가 - 대규모 데이터베이스 시스템에 적합 | - 온라인 거래 시스템
- 다중 사용자 편집 시스템 |
Share article