트랜잭션이란?
트랜잭션이란 데이터베이스 작업의 단위를 의미하며, 몇개의 Transact-SQL문으로 이루어진다.
가장 흔한 예로 계좌이체 작업이 있다.
A라는 계좌에서 B계좌로 이체하는 작업은 A 계좌의 잔액을 읽어서 이체할 금액 차감이 가능하면 차감 후 잔액을 A계좌에 기록하고 B계좌에 이체금액만큼 더하여 그 결과를 B계좌에 기록하면 모든 작업이 완료된다.
하지만 A계좌의 차감까지 진행된 상태에서 전원이 나가는 등의 장애로 B계좌에 더해진 금액이 기록되지 않으면 문제가 발생한다.
이러한 문제 발생을 막기 위해서는 위의 개별적인 작업들을 하나로 묶어 트랜잭샌으로 구성하게 된다.
이렇게 하나의 트랜잭션으로 묶이게 되면 전체 작업을 수행하는 도중 오류 발생시 초기 상태로 되돌려 피해를 줄이게 할 수 있다.
트랜잭션은 일반적으로 ACID(Atomicity, Consistency, Isolation, Durability)와 같은 특성을 가진다.
원자성(Atomicity)
일반적으로 원자란 더 이상 나눌 수 없는 가장 작은 단위의 개념을 일컫는 말이다. 이처럼 트랜잭션도 작업 프로세스를 구성하는 하나의 원자로서 더 이상 나눌 수 없는 단위의 것이다. 이러한 원자적인 성격은 All or Nothing이라는 말로 표현되기도 하는데 이는 트랜잭션이 전부 성공하거나 아니면 전부 실패해야만 한다는 것이다. 따라서 트랜잭션의 결과는 성공과 실패뿐, 어떤 하위 부분만 부분적으로 성공해서는 트랜잭션이라 할 수 없다.
일관성(Consistency)
하나의 트랜잭션이 성곡적으로 완료되기 위해서는 트랜잭션에 이용된 모든 데이터에 일관성이 부여되어야만 한다. 일관성이 부여된다는 의미는 데이터베이스의 무결성 원칙에 트랜잭션이 위배되어서는 안된다는 의미이다. 따라서 이러한 무결성을 위배하는 트랜잭션은 반드시 취소되어야만 한다.
고립성(Isolation)
현재의 트랜잭션에 의해 변경되고 있는 데이터 영역이 다른 사용자나 트랜잭션의 변경 프로세스로부터 분리되어야만 한다는 것을 의미한다.
보존성(Durability)
트랜잭션이 정상적으로 종료된 후에는 시스템 오류가 발생하더라도 데이터를 안정적으로 저장시키는 특성을 말한다.
트랜잭션의 종류
자동 커밋 트랜잭션
DELETE, INSERT, SELECT문이나 CREATE TABLE문과 같이 개별 명령문이 바로 하나의 트랜잭션을 의미하는 경우이다.
-- 자동 커밋 트랜잭션 DELETE TB_Member WHERE isValid='N'; -- 명시적 트랜잭션 BEGIN TRAN DELETE TB_Member WHERE user_id='tester'; COMMIT TRAN
명시적 트랜잭션과 마찬가지로 BEGIN TRAN문과 COMMIT문이 명령문 앞뒤에 자동으로 붙어 수행된다.
오라클의 경우 명시적으로 Commit문을 통해 트랜잭션을 종료하도록하는데 비하여 SQL은 자동으로 이러한 COMMIT문을 붙여서 이용한다.
명시적 트랜잭션
트랜잭션은 BEGIN TRANSACTION 혹은 간단히 BEGIN TRAN 문을 통해 시작하고 COMMIT TRANSACTION 혹은 COMMIT TRAN문을 통해 종료시킬 수 있다.
트랜잭션 중에 오류 발생시 ROLLBACK TRANSACTION 혹은 ROLLBACK TRAN문을 사용하여 트랜잭션을 취소시킬 수 있다.
BEGIN TRAN UPDATE TB_Account SET money = money - 100000 WHERE id='A' UPDATE TB_Account SET money = money + 100000 WHERE id='B' INSERT TB_Account_Log(id, money)VALUES('A',-100000) INSERT TB_Account_Log(id, money)VALUES('B',100000) IF (@@ERROR <> 0) ROLLBACK TRAN ELSE COMMIT TRAN GO
추적해야할 에러가 많을 경우 일일이 글로벌 변수인 @@ERROR를 확인하는 것은 쉽지 않다.
이때는 런터임 에러가 발생했을 경우 트랜잭션을 롤백시켜주는 옵션인 SET XACT_ABORT ON | OFF를 사용하면 된다.
SET XACT_ABORT OFF GO BEGIN TRAN UPDATE TB_Account SET money = money - 100000 WHERE id='A' UPDATE TB_Account SET money = money + 100000 WHERE id='B' INSERT TB_Account_Log(id, money)VALUES('A',-100000) INSERT TB_Account_Log(id, money)VALUES('B',100000) COMMIT TRAN GO
암시적 트랜잭션 (Implicit Transaction)
암시적 트랜잭션은 SET IMPLICT_TRANSACTION 선언을 통해서 선언할 수 있다.
암시적 트랜잭션 모드는 커넥션 레벨 설정으로 해당 커넥션에서 데이터를 수정하는 쿼리를 실행하면 자동으로 하나의 트랜잭션이 시작된 것으로 인식하고 사용자가 COMMIT 혹은 ROLLBACK문으로 명시적으로 트랜잭션을 종료시키기 전까지는 트랜잭션이 진행하는 것으로 인식하게 된다.
중첩 트랜잭션 (Nested Transaction)
트랜잭션이 줍첩되는 경우에는 원자성을 위반하게 된다. 그래서 특별한 이유가 없는 이상 트랜잭션을 중첩시키는 것을 피하는 것이 좋다.
중첩 트랜잭션과 중첩되지 않은 트랜잭션 모두 하나의 오류라도 발생하면 전체 트랜잭션을 취소시킨다는 점에서 동일하기 대문에 굳이 중첩 트랜잭션을 이용할 필요는 없을 것이다.
트랜잭션 저장점 (Transaction Savepoint)
트랜잭션에 에러가 발생하면 전체 트랜잭션이 모두 취소된다. 즉 All OR Nothing이지만 트랜잭션 일부만 Rollback 할 수 있는 기능이 제공된다.
이것이 바로 트랜잭션 저장점이다.
SAVE TRANSACTION savepoint_name문을 이용해 트랜잭션 저장점을 생성한 후
ROLLBACK TRANSACTION savepoint_name문을 사용하여 저장점까지만 ROLLBACK하도록 할 수 있다.
BEGIN TRAN TranMaster UPDATE TB_Account SET money = money - 100000 WHERE id='A' UPDATE TB_Account SET money = money + 100000 WHERE id='B' SAVE TRAN TransSubSave INSERT TB_Account_Log(id, money)VALUES('A',-100000) INSERT TB_Account_Log(id, money)VALUES('B',100000) ROLLBACK TRAN TranSubSave COMMIT TRAN TranMaster