트랜잭션 제어
트랜잭션을 시작하고, 확정하고, 취소하는 명령어를 다룹니다. Oracle과 MySQL은 트랜잭션 시작 방식이 다르므로 주의가 필요합니다. 정확한 트랜잭션 제어를 모르면 데이터가 의도치 않게 확정되거나 유실될 수 있습니다.
COMMIT과 ROLLBACK
COMMIT은 트랜잭션의 모든 변경을 확정(영구 반영)합니다. ROLLBACK은 트랜잭션의 모든 변경을 취소하여 원래 상태로 되돌립니다.
-- Oracle은 DML 실행 시 자동으로 트랜잭션 시작 (수동 커밋 모드)
UPDATE accounts SET balance = balance - 100000 WHERE id = 1;
UPDATE accounts SET balance = balance + 100000 WHERE id = 2;
-- 성공하면 확정
COMMIT;
-- 또는 문제가 있으면 취소
ROLLBACK;-- MySQL InnoDB는 기본 자동 커밋 (autocommit=1)
-- 명시적 트랜잭션:
START TRANSACTION;
UPDATE accounts SET balance = balance - 100000 WHERE id = 1;
UPDATE accounts SET balance = balance + 100000 WHERE id = 2;
COMMIT;
-- 또는
ROLLBACK;| 명령어 | 동작 | 잠금 | 비용 |
|---|---|---|---|
| COMMIT | 모든 변경을 영구 반영 | 해제 | 로그 플러시 (빠름) |
| ROLLBACK | 모든 변경을 취소 | 해제 | 언두 적용 (느릴 수 있음) |
Oracle vs MySQL 자동 커밋 차이
| 항목 | Oracle | MySQL (InnoDB) |
|---|---|---|
| 기본 모드 | 수동 커밋 | 자동 커밋 (autocommit=1) |
| 트랜잭션 시작 | DML 실행 시 자동 | START TRANSACTION 또는 BEGIN |
| COMMIT 하지 않으면 | 세션 종료 시 ROLLBACK | 각 DML이 즉시 자동 COMMIT |
| DDL 실행 시 | 암묵적 COMMIT 발생 | 암묵적 COMMIT 발생 |
Oracle에서 UPDATE 후 COMMIT을 안 하면 다른 세션에서 변경된 데이터를 볼 수 없고, 세션이 종료되면 변경이 취소됩니다. MySQL은 기본적으로 각 SQL이 자동 커밋되므로, 명시적 트랜잭션을 쓰려면 START TRANSACTION을 선언해야 합니다.
-- 현재 설정 확인
SELECT @@autocommit; -- 1 = 자동 커밋 ON
-- 세션 단위로 자동 커밋 끄기
SET autocommit = 0;
-- → 이후 모든 DML은 명시적 COMMIT/ROLLBACK 필요
-- → Oracle과 유사한 동작
-- 다시 켜기
SET autocommit = 1;
-- START TRANSACTION은 autocommit 설정과 관계없이
-- 무조건 명시적 트랜잭션 시작
START TRANSACTION;
-- autocommit=1이어도 COMMIT/ROLLBACK까지 하나의 트랜잭션SAVEPOINT와 부분 롤백
SAVEPOINT는 트랜잭션 중간에 체크포인트를 설정하여, 전체가 아닌 특정 지점까지만 롤백할 수 있게 합니다.
-- 주문 처리 트랜잭션
INSERT INTO orders (id, user_id, total)
VALUES (orders_seq.NEXTVAL, 1, 50000);
SAVEPOINT after_order;
INSERT INTO order_items (id, order_id, product_id, quantity, price)
VALUES (items_seq.NEXTVAL, orders_seq.CURRVAL, 101, 2, 25000);
-- 재고 부족 발견!
ROLLBACK TO after_order;
-- → order_items INSERT만 취소, orders INSERT는 유지
-- 다른 상품으로 대체
INSERT INTO order_items (id, order_id, product_id, quantity, price)
VALUES (items_seq.NEXTVAL, orders_seq.CURRVAL, 102, 1, 50000);
COMMIT;SAVEPOINT 규칙
-- Oracle
SAVEPOINT point_name;
ROLLBACK TO point_name;
-- MySQL
SAVEPOINT point_name;
ROLLBACK TO SAVEPOINT point_name;
RELEASE SAVEPOINT point_name; -- 명시적 삭제
-- PostgreSQL
SAVEPOINT point_name;
ROLLBACK TO SAVEPOINT point_name;
RELEASE SAVEPOINT point_name;
-- SQL Server (트랜잭션 이름 방식)
SAVE TRANSACTION point_name;
ROLLBACK TRANSACTION point_name;DDL과 암묵적 커밋
Oracle과 MySQL 모두 DDL(CREATE, ALTER, DROP)을 실행하면 현재 트랜잭션이 자동으로 커밋됩니다.
UPDATE accounts SET balance = balance - 100000 WHERE id = 1;
-- 아직 COMMIT 안 함
CREATE TABLE temp_log (msg VARCHAR2(200));
-- DDL 실행 → 암묵적 COMMIT 발생!
-- 위의 UPDATE가 자동으로 확정됨
ROLLBACK;
-- 이미 커밋되었으므로 롤백 불가!-- PostgreSQL: DDL도 트랜잭션 안에서 롤백 가능
BEGIN;
CREATE TABLE new_table (id SERIAL, name TEXT);
INSERT INTO new_table (name) VALUES ('test');
-- 확인 후 문제 발견
ROLLBACK;
-- → CREATE TABLE도 취소됨! (Oracle/MySQL에서는 불가)트랜잭션 제어와 잠금
트랜잭션이 끝나기 전까지(COMMIT 또는 ROLLBACK) 변경한 행에 대한 잠금이 유지됩니다.
1. 트랜잭션은 가능한 짧게 유지
→ 잠금 시간을 최소화하여 동시성 확보
2. 사용자 입력을 기다리는 중에 트랜잭션을 열어두지 않기
→ "SELECT ... FOR UPDATE" 후 사용자 확인 대기 → 위험!
3. 대량 DML은 배치로 나누어 중간 COMMIT
→ 100만 건 UPDATE를 한 트랜잭션으로 → 언두/로그 폭증
→ 1000건씩 나누어 COMMIT → 안전
4. COMMIT 빈도와 데이터 정합성의 균형
→ 너무 잦은 COMMIT → 원자성 깨질 수 있음
→ 너무 드문 COMMIT → 잠금 + 리소스 부담읽기 전용 트랜잭션과 읽기/쓰기 트랜잭션
-- Oracle
SET TRANSACTION READ ONLY;
-- → SELECT만 허용, DML 실행 시 에러
-- → 트랜잭션 시작 시점의 일관된 스냅샷 읽기 (Consistent Read)
-- MySQL
START TRANSACTION READ ONLY;
-- → InnoDB 최적화: 트랜잭션 ID 할당 생략 → 성능 향상
-- PostgreSQL
BEGIN TRANSACTION READ ONLY;
-- SQL Server
SET TRANSACTION ISOLATION LEVEL SNAPSHOT;
BEGIN TRANSACTION;
-- → 읽기 전용으로 명시하는 별도 구문은 없으나
-- → SNAPSHOT 격리로 유사한 효과1. 일관된 스냅샷: 트랜잭션 시작 시점의 데이터를 일관되게 조회
→ 장기 조회 중 다른 트랜잭션이 데이터를 변경해도
조회 결과는 변하지 않음
2. 성능 최적화: DML 불가능하므로 잠금/언두 오버헤드 감소
3. 보고서 생성 시 유용:
BEGIN READ ONLY;
SELECT ... -- 대시보드 데이터 조회 1
SELECT ... -- 대시보드 데이터 조회 2
SELECT ... -- 대시보드 데이터 조회 3
COMMIT; -- 세 쿼리 모두 동일 시점의 데이터 보장트랜잭션 제어와 애플리케이션 패턴
실무에서 트랜잭션 제어를 잘못하면 데이터 정합성 문제나 성능 문제가 발생합니다.
DBMS별 트랜잭션 제어 비교 종합
자율 트랜잭션 (Autonomous Transaction)
Oracle에서는 현재 트랜잭션과 독립적인 별도 트랜잭션을 실행할 수 있습니다.
CREATE OR REPLACE PROCEDURE log_event(p_msg VARCHAR2) IS
PRAGMA AUTONOMOUS_TRANSACTION;
BEGIN
INSERT INTO event_log (msg, log_time)
VALUES (p_msg, SYSDATE);
COMMIT; -- 메인 트랜잭션과 독립적으로 커밋
END;
-- 메인 트랜잭션
BEGIN
UPDATE accounts SET balance = balance - 100 WHERE id = 1;
log_event('출금 시도'); -- 별도 트랜잭션으로 로그 기록
-- 에러 발생!
ROLLBACK;
-- → accounts UPDATE는 롤백
-- → event_log INSERT는 이미 커밋되어 유지됨!
END;* 감사(Audit) 로그: 메인 트랜잭션 실패해도 로그는 남겨야 함
* 에러 로그: 예외 발생 시 에러 정보를 DB에 기록
* 시퀀스 관리: 채번은 롤백되면 안 됨
다른 DBMS에서의 대안
MySQL: 별도 커넥션으로 로그 INSERT
PostgreSQL: dblink 또는 별도 커넥션트랜잭션 제어 흐름 정리
정리
| 개념 | 핵심 내용 |
|---|---|
| COMMIT | 변경 확정, 로그 flush로 빠름 |
| ROLLBACK | 변경 취소, 언두 적용으로 느릴 수 있음 |
| SAVEPOINT | 트랜잭션 중간 체크포인트, 부분 롤백 가능 |
| 자동 커밋 | Oracle=수동, MySQL=자동(기본) |
| 암묵적 커밋 | DDL 실행 시 자동 커밋 (PostgreSQL 제외) |
| 잠금 유지 | COMMIT/ROLLBACK까지 잠금 유지 |
| 읽기 전용 | 일관된 스냅샷 읽기, DML 차단 |
트랜잭션 제어의 핵심은 짧고 명확한 트랜잭션을 유지하는 것입니다. 트랜잭션이 길어지면 잠금이 오래 유지되어 동시성이 저하되고, 대량 변경 후 ROLLBACK은 매우 비용이 큽니다. 항상 COMMIT과 ROLLBACK을 명시적으로 제어하고, DDL에 의한 암묵적 커밋에 주의해야 합니다.
다음 절에서는 트랜잭션의 상태 전이와 직렬 가능성을 다루겠습니다.