트랜잭션이 탄생한 배경(?????)
- 은행을 예로 들어보자
- A계좌에 100만원 B계좌에 0원이 있다
- A계좌에서 B계좌로 50만원을 이체하려 한다
- 데이터 베이스 SQL은 A,B 두 테이블에 update문을 실행해야 한다
- 그런데 서버에 문제가 생겨서 B테이블에 update가 실행되지 않았다면?
- A 계좌는 50만원이 줄었는데 B 계좌는 그대로 0원이 된다
- 이런 사고를 막기위해 2개의 방법이 있다.
1. 어떤 상황에서든 update문을 실행한다
2. update를 실행하기 전 상태를 유지할 수 있어야 한다.
트랜잭션이란?
- 더이상 분할할 수 없는 최소 수행 단위
- 하나의 작업 또는 밀접하게 연관된 작업을 수행하기 위해 한 개 이상의 데이터 조작 명령어(DML)로 이루어 진다.
- 어떤 기능 한가지를 수행하는 SQL문 덩어리
- 트랜직션은 하나의 트랜잭션 나에 있는 여러 명령어를 한번에 수행하여 작업을 완료하거나, 모든 작업을 취소한다.
- 트랜잭션을 제어하기 위해 사용하는 명렁어를 TCL이라 한다.
- 트랜잭션은 데이터베이스 계정을 통해 접속하는 동시에 시작된다
ROLLBACK
- 데이터베이스의 모든 작업을 취소하고 싶을때 사용
- 현재 트랜잰션에 포함된 데이터 조작 관련 명령어의 수행을 모두 취소한다
COMMIT
- 지금까지 수행한 트랜잭션 명령어를 데이터 베이스에 영구히 반영할때 사용
- commit은 실행한 내용의 반영을 되돌릴수 없으므로 정말 신중하게 사용해야 한다
트랜잭션의 특징
- 원자성(atomicity) : 트랜잭션의 모든 연산들이 정상적으로 수행 완료되거나 아니면 전혀 어떠한 연산도 수행되지 않은 상태를 보장해야 한다.
- 일관성(consistency) : 성공적으로 수행된 트랜잭션은 정당한 데이터들만을 데이터베이스에 반영해야 한다.
- 독립성(isolation) : 여러 트랜잭션이 동시에 수행되더라도 각각의 트랜잭션은 다른 트랜잭션의 수행에 영향을 받지 않고 독립적으로 수행되어야 한다.
즉, 한 트랜잭션의 중간 결과가 다른 트랜잭션에게는 숨겨져야 한다는 의미
- 지속성(durability) : 트랜잭션이 성공적으로 완료되어 커밋되고 나면, 해당 트랜잭션에 의한 모든 변경은 향후에 어떤 소프트웨어나 하드웨어 장애가 발생되더라도 보존되어야 한다.
트랜잭션의 격리 수준
Isolation level
- 트랜잭션에서 일관성 없는 데이터를 허용하도록 하는 수준
Isolation level의 필요성
- 데이터베이스는 ACID 특징과 같이 트랜잭션이 독립적인 수행을 하도록 한다.
- 따라서 Locking을 통해, 트랜잭션이 DB를 다루는 동안 다른 트랜잭션이 관여하지 못하도록 막는 것이 필요하다.
- 하지만 무조건 Locking으로 동시에 수행되는 수많은 트랜잭션들을 순서대로 처리하는 방식으로 구현하게 되면 데이터베이스의 성능은 떨어지게 될 것이다.
- 그렇다고 해서, 성능을 높이기 위해 Locking의 범위를 줄인다면, 잘못된 값이 처리될 문제가 발생하게 된다.
따라서 최대한 효율적인 Locking 방법이 필요함!
Isolation level 종류
Read Uncommitted (레벨 0)
- SELECT 문장이 수행되는 동안 해당 데이터에 Shared Lock이 걸리지 않는 계층
- 트랜잭션에 처리중이거나, 아직 Commit되지 않은 데이터를 다른 트랜잭션이 읽는 것을 허용함
- 사용자1이 A라는 데이터를 B라는 데이터로 변경하는 동안 사용자2는 아직 완료되지 않은(Uncommitted) 트랜잭션이지만 데이터B를 읽을 수 있다
데이터베이스의 일관성을 유지하는 것이 불가능함
Read Committed (레벨 1)
- SELECT 문장이 수행되는 동안 해당 데이터에 Shared Lock이 걸리는 계층
- 트랜잭션이 수행되는 동안 다른 트랜잭션이 접근할 수 없어 대기하게 됨
- Commit이 이루어진 트랜잭션만 조회 가능
- 대부분의 SQL 서버가 Default로 사용하는 Isolation Level임
- 사용자1이 A라는 데이터를 B라는 데이터로 변경하는 동안 사용자2는 해당 데이터에 접근이 불가능함
Repeatable Read (레벨 2)
- 트랜잭션이 완료될 때까지 SELECT 문장이 사용하는 모든 데이터에 Shared Lock이 걸리는 계층
- 트랜잭션이 범위 내에서 조회한 데이터 내용이 항상 동일함을 보장함
- 다른 사용자는 트랜잭션 영역에 해당되는 데이터에 대한 수정 불가능
- MySQL에서 Default로 사용하는 Isolation Level
Serializable (레벨 3)
- 트랜잭션이 완료될 때까지 SELECT 문장이 사용하는 모든 데이터에 Shared Lock이 걸리는 계층
- 완벽한 읽기 일관성 모드를 제공함
- 다른 사용자는 트랜잭션 영역에 해당되는 데이터에 대한 수정 및 입력 불가능
선택 시 고려사항
- Isolation Level에 대한 조정은, 동시성과 데이터 무결성에 연관되어 있음
- 동시성을 증가시키면 데이터 무결성에 문제가 발생하고, 데이터 무결성을 유지하면 동시성이 떨어지게 됨
- 레벨을 높게 조정할 수록 발생하는 비용이 증가함
낮은 단계 Isolation Level을 활용할 때 발생하는 현상들
-
Dirty Read
- 커밋되지 않은 수정중인 데이터를 다른 트랜잭션에서 읽을 수 있도록 허용할 때 발생하는 현상
- 어떤 트랜잭션에서 아직 실행이 끝나지 않은 다른 트랜잭션에 의한 변경사항을 보게되는 경우
* 발생 Level: Read Uncommitted
-
Non-Repeatable Read
- 한 트랜잭션에서 같은 쿼리를 두 번 수행할 때 그 사이에 다른 트랜잭션 값을 수정 또는 삭제하면서 두 쿼리의 결과가 상이하게 나타나는 일관성이 깨진 현상
* 발생 Level: Read Committed, Read Uncommitted
-
Phantom Read
- 한 트랜잭션 안에서 일정 범위의 레코드를 두 번 이상 읽었을 때, 첫번째 쿼리에서 없던 레코드가 두번째 쿼리에서 나타나는 현상
- 트랜잭션 도중 새로운 레코드 삽입을 허용하기 때문에 나타나는 현상임
* 발생 Level: Repeatable Read, Read Committed, Read Uncommitted
LOCK
- 조작중인 데이터를 다른 세션은 조작할 수 없도록 접근을 보류시키는 것
- 화장실 줄 서있는것과 비슷(응?
같이 들어가서 큰일 치룰 수는 없잖아?)
- HANG : 특정 세션에서 데이터 조작이 완료돌 때까지 다른 세션에서 해당 데이터 조작을 기다리는 현상
트랜잭션의 교착 상태
- 복수의 트랜잭션을 사용하다보면 교착상태가 일어날수 있다.
- 교착상태란 두 개 이상의 트랜잭션이 특정 자원(테이블 또는 행)의 잠금(Lock)을 획득한 채 다른 트랜잭션이 소유하고 있는 잠금을 요구하면 아무리 기다려도 상황이 바뀌지 않는 상태가 되는데, 이를 교착상태라고 한다.
교착 상태의 빈도를 낮추는 방법
- 트랜잭션을 자주 커밋한다.
- 정해진 순서로 테이블에 접근한다. 위에서 트랜잭션 1 이 테이블 B -> A 의 순으로 접근했고, 트랜잭션 2 는 테이블 A -> B의 순으로 접근했다. 트
- 랜잭션들이 동일한 테이블 순으로 접근하게 한다.
- 읽기 잠금 획득 (SELECT ~ FOR UPDATE)의 사용을 피한다.
- 한 테이블의 복수 행을 복수의 연결에서 순서 없이 갱신하면 교착상태가 발생하기 쉽다, 이 경우에는 테이블 단위의 잠금을 획득해 갱신을 직렬화 하면 동시성은 떨어지지만 교착상태를 회피할 수 있다.
오라클로 배우는 데이터베이스 입문
DBMS는 어떻게 트랜잭션을 관리할까?