제2절 트랜잭션

  • 트랜잭션(Transaction)은 업무 처리를 위한 논리적인 작업 단위이다.

1. 트랜잭션의 특징

  • 원자성(Atomicity)
    트랜잭션은 더 이상 분해가 불가능한 업무의 최소단위이므로, 전부 처리되거나 하나도 처리되지 않아야 함.
  • 일관성(Consistency)
    일관된 상태의 데이터베이스에서 하나의 트랜잭션을 성공적으로 완료하고 나면 그 데이터베이스는 여전히 일관된 상태여야 함.
  • 격리성(Isolation)
    실행 중인 트랜잭션의 중간 결과를 다른 트랜잭션이 접근할 수 없음
  • 영속성(Durability)
    트랜잭션이 일단 실행을 성공적으로 완료하면 그 결과는 데이터베이스에 영속적으로 저장.

2. 트랜잭션 격리성

가. 낮은 단계의 격리성 수준에서 발생할 수 있는 현상들
1) Dirty Read

 다른 트랜잭션에 의해 수정됐지만 아직 커밋되지 않은 데이터를 읽는 것을 의미.

 변경 후 아직 커밋되지 않은 값을 읽었는데 변경을 가한 트랜잭션이 최종적으로 롤백된다면 그 값을 읽은 트랜잭션은 비일관된 상태에 놓이게 됨.

2) Non-Repetable Read

 한 트랜잭션 내에서 같은 쿼리를 두 번 수행했는데, 그 사이에 다른 트랜잭션이 값을 수정 또는 삭제하는 바람에 두 쿼리 결과가 다르게 나타나는 현상

<TX1>
<TX2>
T1
SELECT 잔고

INTO :balance

&nbsp; FROM 계좌

WHERE 계좌번호 = 123;

\--> 잔고 : 55,000원{}
T2
UPDATE 계좌

&nbsp;&nbsp;&nbsp;&nbsp; SET 잔고 = 잔고 - 50000

&nbsp; WHERE 계좌번호 = 123;

\--> 잔고 : 5,000{}
T3
COMMIT;
T4
UPDATE 계좌

&nbsp;&nbsp;&nbsp;&nbsp; SET 잔고 = 잔고 - 10000

&nbsp; WHERE 계좌번호 = 123

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; AND 잔고 >= 10000;

\--> 잔고가 부족하다는 메시지를 받게 됨
T5
IF sql%rowcount = 0 THEN

&nbsp; alert('잔고가 부족합니다');

END IF;
T6
COMMIT;

<그림 3-2-1> Non-Repeatable Read

3) Phantom Read
  • 한 트랜잭션 내에서 같은 쿼리를 두 번 수행했는데, 첫 번째 쿼리에서 없던 유령(Phantom) 레코드가 두 번째 쿼리에서 나타나는 현상
<TX1>
<TX2>
T1
INSERT INTO 지역별고객

SELECT 지역, COUNT(*)

&nbsp;&nbsp; FROM 고객

&nbsp; GROUP BY 지역;
T2
INSERT INTO 고객(고객번호, 이름, 지역, 연령대, ...)

VALUES (:a, :b, :c, :d, ...);
T3
COMMIT;
T4
INSERT INTO 연령대별고객

SELECT 연령대, COUNT(*)

&nbsp;&nbsp; FROM 고객

&nbsp; GROUP BY 연령대;
T5
COMMIT;
  • TX1 트랜잭션이 지역별고객과 연령대별고객을 연속해서 집계하는 도중에 새로운 고객이 TX2 트랜잭션에 의해 등록
  • 그 결과, 지역별고객과 연령대별 고객 두 집계 테이블을 통해 총고객수를 조회하면 서로 결과 값이 다름
나. 트랜잭션 격리성 수준(Transaction Isolation Level) - ANSI/ISO SQL 표준에서 정의
  • Read Uncommitted
    트랜잭션에서 처리 중인 아직 커밋되지 않은 데이터를 다른 트랜잭션이 읽는 것을 허용
  • Read Committed
    트랜잭션이 커밋되어 확정된 데이터만 다른 트랜잭션이 읽도록 허용함으로써 Dirty Read를 방지해줌.
    커밋된 데이터만 읽더라도 Non-Repeatable Read와 Phantom Read 현상을 막지는 못함.
  • Repeatable Read
    트랜잭션 내에서 쿼리를 두 번 이상 수행할 때, 첫 번째 쿼리에 있던 레코드가 사라지거나 값이 바뀌는 현상을 방지해 줌
    이는 트랜잭션 격리성 수진이 Phantom Read 현상을 막지는 못함.
  • Serializable Read
    트랜잭션 내에서 쿼리를 두 번 이상 수행할 대, 첫 번째 쿼리에 있던 레코드가 사라지거나 값이 바뀌지 않음은 물론 새로운 레코드가 나타나지도 않음
레벨
Dirty Read
Non-Repeatable Read
Phantom Read
Read Uncommitted
가능가능가능
Read Committed
불가능가능가능
Repeatable Read
불가능불가능가능
Serializable Read
불가능불가능불가능
  • &nbsp;모든 DBMS가 4가지 레벨을 다 지원하지 않음
  • SQL Server와 DB2는 4가지 레벨을 다 지원하지만 오라클은 Read Committed와 Serializable Read만 지원
    (Oracle에서 Repeatable Read를 구현하려면 for update 구문을 이용하면 된다.)
  • 대부분의 DBMS는 Read Committed를 기본 트랜잭션 격리성 수준으로 사용
  • 다중 트랜잭션 환경에서 DBMS가 제공하는 기능을 이용해 동시성을 제어하려면 트랜잭션 시작 전에 명시적으로 SET TRANSACTION 명령어를 수행하면 됨

\* SQL Server

set transaction isolation level read serializable;

\* ORACLE

alter session set isolation_level = serializable;



  • 트랜잭션 격리성 수준을 Repeatable Read나 Serializable Read로 올리면 ISO에서 정한 기준을 만족해야 하며, 대부분 DBMS가 이를 구현하기 위해
    Locking 매커니즘에 의존한다.
  • 위의 <그림 3-2-1>에서, TX1 트랜잭션을 Repeatable Read 모드에서 실행했다고 하면, T1 시점의 쿼리에서 설정한 공유 Lock을 T6 시점까지 유지
    하므로, TX2의 Update는 T6 시점까지 대기가 발생하는 형식의 Locking 매커니즘
  • 이와 같이 수행할 경우 동시성이 떨어진다. 이에 대안으로 다중 버전 동시성 제어를 채택하는 DBMS가 조금씩 늘고 있다.
  • 이는 '스냅샷 격리성 수준(Snapshot Isolation Level)'이라고도 불림.
    현재 진행 중인 트랜잭션에 의해 변경된 데이터를 읽고자 할 대는 변경 이전 상태로 되돌린 버전을 읽음.
    변경이 아직 확정되지 않은 값을 읽으려는 것이 아니므로 공유 Lock을 설정하지 않아도 됨.
    이로 인해 읽는 세션과 변경하는 세션이 서로 간섭현상을 일으키지 않음.