Skip to content

Transaction

트랜잭션은 꼭 여러 개의 변경 작업을 수행하는 쿼리가 아니더라도, 논리적인 작업 자체가 적용(Commit)되거나, 모두 적용되지 않아야(Rollback) 보장한다고 할 수 있다.

트랜잭션은 ACID의 특성을 가지고 있으며, 그 의미와 특징, 그리고 보장 방법을 간단히 설명하면 아래와 같다.

ACID 특성설명InnoDB 보장 방식
원자성(Atomicity)트랜잭션의 모든 작업이 정상적으로 모두 성공하거나 모두 실패하는 것Undo-log를 통한 트랜잭션 이전 상태로의 복구로 원자성 보장
일관성(Consistency)트랜잭션을 수행 전과 수행 후에 데이터베이스의 일관된 상태 유지유니크 제약조건, 외래키 제약조건 등의 적용으로 일관성 보장
고립성(Isolation)트랜잭션 수행 중 다른 트랜잭션의 작업이 데이터 변경을 일으키지 못하는 상태잠금(Lock)과 MVCC(Multi-Version Concurrency Control) 매커니즘 사용
지속성(Durability)트랜잭션 완료 후 결과의 영구적 반영시스템 장애 시, Redo-log에서 커밋된 트랜잭션의 읽기를 통한 지속성 보장

DDL(CREATE, ALTER, DROP, TRUNCATE 등)은 DML과 달리 테이블 구조 자체를 변경하는 명령이기 때문에, 트랜잭션 처리 방식도 다르다.

  • MySQL/InnoDB를 포함한 대부분의 DBMS에서 DDL 명령은 실행 시 암묵적으로 COMMIT이 수행
  • START TRANSACTION 내에서 DDL을 실행하면, 그 직전까지의 DML 변경 내역까지 함께 커밋되어 이후 ROLLBACK이 무효화
  • PostgreSQL은 트랜잭션 내 DDL을 지원하여 롤백이 가능하지만, MySQL은 이 동작을 지원하지 않음
START TRANSACTION;
INSERT INTO users (name)
VALUES ('Alice');
-- Alice는 아직 커밋되지 않은 상태
ALTER TABLE users
ADD COLUMN phone VARCHAR(20);
-- DDL 실행 → 암묵적 COMMIT 발생 → Alice INSERT도 함께 커밋됨
ROLLBACK;
-- 이미 커밋되었으므로 Alice 데이터는 롤백되지 않음

DDL이 암묵적 커밋을 강제하는 이유는 내부 처리 방식 자체가 DML과 다르기 때문이다.

  • 물리적 재구성: 테이블스페이스에 새 컬럼 공간을 확보하고 기존 레코드를 새 포맷으로 재작성하며, 영향 받는 인덱스도 재구성
  • Undo 로그 부재: DML은 변경 전 행 데이터를 Undo 로그에 기록하지만, DDL은 구조 변경 자체에 대한 행 단위 Undo 기록이 없음
  • 의존 객체 연쇄: 새 스키마를 참조하는 뷰·외래키·트리거·저장 프로시저·실행 계획 캐시가 모두 영향을 받으며, 이를 역순으로 되돌리는 비용이 과도
flowchart TB
subgraph DML["DML 경로 - UPDATE users SET name = 'Bob' WHERE id = 1"]
D1["변경 전 데이터\nname = 'Alice'"] --> D2[Undo 로그에 기록]
D3["변경 내용\nname → 'Bob'"] --> D4[Redo 로그에 기록]
D2 --> D5["ROLLBACK 시\nUndo 로그로 원복"]
end
subgraph DDL["DDL 경로 - ALTER TABLE users ADD COLUMN age INT"]
A1[테이블 정의 변경] --> A2[메타데이터 테이블 갱신]
A2 --> A3["Undo 로그 없음\n롤백 불가"]
end
classDef dml fill: #4a9eff,color: #000
classDef ddl fill: #f5a623,color: #000
class D1,D2,D3,D4,D5 dml
class A1,A2,A3 ddl

애플리케이션 개발 시 트랜잭션의 범위는 가능한 한 작게 유지하는 것이 데이터베이스 성능에 중요하다.

  • 트랜잭션이 유지되는 동안 데이터베이스 커넥션을 점유
  • 접근하는 데이터에 대해 잠금 획득 가능성

위와 같은 이유로 트랜잭션 범위가 넓고 실행 시간이 길어질수록, 커넥션 점유 시간과 잠금 유지 시간이 길어져 전체적인 시스템 동시성을 저하시키고 성능 저하의 주된 원인이 될 수 있다.

1) 처리 시작
=> 데이터베이스 커넥션 획득 및 트랜잭션 시작 (BEGIN)
2) 사용자의 로그인 여부 확인 (애플리케이션 로직)
3) 사용자의 글쓰기 내용의 오류 여부 확인 (애플리케이션 로직)
4) 첨부로 업로드된 파일 확인 및 서버에 저장 (파일 I/O)
5) 사용자의 입력 내용을 DBMS에 저장 (DB 작업)
6) 첨부 파일 정보를 DBMS에 저장 (DB 작업)
7) 저장된 내용 또는 기타 정보를 DBMS에서 조회 (DB 작업)
8) 게시물 등록에 대한 알림 메일 발송 (외부 시스템 연동)
9) 알림 메일 발송 이력을 DBMS에 저장 (DB 작업)
<= 트랜잭션 종료 (COMMIT) 및 커넥션 반납
10) 처리 완료

위 프로세스의 문제점은 다음과 같다.

  • 불필요한 로직 포함
    • 2, 3, 4번 과정은 실제 DB 데이터를 변경하지 않는 애플리케이션 로직 또는 파일 시스템 작업
    • 이 시간 동안 트랜잭션을 유지하는 것은 불필요하게 커넥션 자원을 점유
  • 외부 시스템 연동
    • 8번의 메일 발송 작업은 외부 SMTP 서버와 통신하는 작업
    • 만약 메일 서버의 응답이 지연되거나 실패할 경우, 해당 시간만큼 데이터베이스의 잠금 상태를 장기화
  • 성격이 다른 작업의 혼합
    • 9번의 메일 발송 이력 저장은 게시물 저장(5, 6번)이라는 핵심 로직과 다른 성격의 작업
    • 게시물 저장은 성공했지만 메일 발송 이력 저장에 실패했다고 해서 게시물 저장까지 롤백할 필요 X

트랜잭션은 순수하게 데이터베이스의 일관성이 반드시 필요한 작업만을 묶어 범위를 최소화해야 한다.

1) 처리 시작
2) 사용자의 로그인 여부 확인
3) 사용자의 글쓰기 내용의 오류 여부 확인
4) 첨부로 업로드된 파일 확인 및 서버에 저장
=> 데이터베이스 커넥션 획득 및 트랜잭션 시작 (BEGIN)
5) 사용자의 입력 내용을 DBMS에 저장
6) 첨부 파일 정보를 DBMS에 저장
<= 트랜잭션 종료 (COMMIT)
7) 저장된 내용 또는 기타 정보를 DBMS에서 조회
8) 게시물 등록에 대한 알림 메일 발송
=> (필요 시) 새로운 트랜잭션 시작 (BEGIN)
9) 알림 메일 발송 이력을 DBMS에 저장
<= 트랜잭션 종료 (COMMIT)
<= 데이터베이스 커넥션 반납
10) 처리 완료

결론적으로 프로그램 코드에서 트랜잭션 범위를 최소화 시켜 커넥션을 가지고 있는 범위를 최소화 시키는 것과, 원격 통신을 하는 작업은 트랜잭션 범위에 포함시키지 않는 것이 좋다.

Last updated:

MySQL