
MySQL의 트랜잭션
트랜잭션의 개념
MySQL에서 Transaction이란 하나의 논리적 작업의 단위이다.
가장 기본이 되는 작업 단위이다.

Transaction은 ACID 원칙(원자성, 일관성, 격리성, 지속성) 을 통해 데이터의 무결성을 보장해준다.
(누군가는 트랜잭션이 굉장히 까다롭고 불편하다고 하지만,
그만큼 트랜잭션은 굉장히 중요하면서 무결성 보장을 해주는 것이다!)
트랜잭션의 상태
트랜잭션의 상태는 크게 두 가지로 구분이 가능하다고 보면 된다.
- Uncommited
- 데이터베이스에 변경 사항이 반영됐으나 아직 영구적으로 저장되지 않은 상태.
- 언제든 ROLLBACK을 실행할 수 있기 때문에 오류가 생긴다면 이전의 상태로 돌아갈 수 있음
- Commited
- COMMIT 명령이 실행되어 모든 변경 사항이 데이터베이스에 영구적으로 반영된 상태
이처럼 COMMIT은 트랜잭션의 논리적 완료를 나타낸다.
데이터베이스가 변경 사항을 영구적으로 보관하겠다고 확정을 보내버리는 행위를 COMMIT이라고 생각하면 된다.
COMMIT과 FLUSH의 구분
트랜잭션을 다룰 때, COMMIT과 FLUSH에 대하여 헷갈리는 경우가 온다.
하지만 둘은 다른 개념이라는 것을 알아두자.
- COMMIT
- 트랜잭션의 논리적인 완료
- 데이터베이스는 변경 사항을 영구적으로 저장하겠다는 "약속"을 하며, ROLLBACK 으로 되돌릴 수 없도록 COMMIT을 올림
- FLUSH
- 메모리에 있는 데이터를 디스크에 물리적으로 강제로 쓰는 작업
- 트랜잭션의 완료와는 다르다!!
- 그렇기 때문에 서버에서 캐시 관리에서 자주 사용함
FLUSH 예제를 확인해보자
FLUSH TABLES : 모든 테이블을 닫고 캐시를 비워 파일 핸들을 해제
FLUSH PRIVILEGES : 권한 테이블을 다시 로드하여 권한 변경 사항 즉시 반영
FLUSH LOGS : 로그 파일을 닫고 새 로그 파일 시작
즉, COMMIT은 데이터의 논리적 확장이며,
FLUSH는 물리적인 쓰기 작업이다.
MySQL에서 AUTOCOMMIT 설정
MySQL 엔진에는 굉장히 다양한 설정들이 존재하는데,
기본적으로 AUTOCOMMIT 모드가 ON(1)으로 설정되어있다.
확인하고 싶다면 다음을 입력하면 된다.
SELECT @@autocommit;
-> 이러한 경우에
INSERT, UUPDATE, DELETE와 같은 DML(데이터 변경) 쿼리가 실행될때마다
자동으로 COMMIT되어 데이터베이스에 반영이 되는것이다
- 만약 AUTOCOMMIT OFF(0)으로 설정한다면?
여러 쿼리를 하나의 트랜잭션으로 묶을 수 있다.
또한 COMMIT과 ROLLBACK을 명시적으로 실행해주어야, 데이터베이스에 해당 사항이 제대로 반영된다.
이 모든느 여러 단계의 변경을 한 번의 논리적 작업 단위로 보장해야할 때 유용하다!!
만약 변경하고 싶다면 다음과 같이 실행하면 된다
SET autocommit = 0;
MySQL의 격리 수준
트랜잭션 격리 수준(Isolation level)은 동시에 실행되는 여러 트랜잭션이 서로의 변경 사항을 "어느정도 볼 수 있는지"를 정의한다.
InnoDB 엔진을 기준으로 MySQL은 다음과 같은 4가지 격리 수준을 지원한다.

| READ UNCOMMITTED | 가장 낮은 격리. 커밋되지 않은 변경 사항을 읽을 수 있음 | 없음 |
| READ COMMITTED | 커밋된 데이터만 읽음. Oracle 기본값 | Dirty Read |
| REPEATABLE READ (기본값) | 트랜잭션 동안 읽은 값이 변하지 않음. MySQL 기본값 | Dirty Read, Non-Repeatable Read |
| SERIALIZABLE | 모든 트랜잭션을 직렬로 실행한 것처럼 보장 | Dirty Read, Non-Repeatable Read, Phantom Read |
- Dirty Read: 커밋되지 않은 데이터를 읽는 현상 (-> 이것이 제대로 관리되지 않으면 데이터 무결성 보장에 위험이 갈 수 있음! )
- Non-Repeatable Read: 한 트랜잭션 내에서 같은 조건으로 두 번 조회 시 결과가 달라짐
- Phantom Read: 같은 조건으로 집계(예: COUNT) 시 새로운 행이 추가되어 결과가 달라짐
이러한 격리 수준에 따라서 일어날 수 있는 위험에 대해서도,
가능한 기능에 대 해서도 굉장히 다양하기 때문에 잘 알아두면 좋다.
가령, Dirty Read의 실제 위험 사례들을 예로 들 수 있는데,
만약 결제 프로세스에 대하여 처리할 때,
재고관리 중에서 주문 프로세스 중에서 재고 수량 +1 해놓고 롤백(ROLLBACK)을 하였는데 , 다른 세션에서는 +1된 수량을 보고 발주를 중단 -> 재고 부족 똔느 초과의 문제가 일어난다.
Spring에서는 주로 어노테이션에 다음과 같은 옵션을 추가함으로써 설정해준다.
// 기본 격리 수준
@Transactional(isolation = Isolation.REPEATABLE_READ)
// 커밋된 것만 읽는다. Dirty Read에 대하여 금지
@Transactional(isolation = Isolation.READ_COMMITED)
// 동시성을 최대로 보장(비용이 크다)
@Transactional(isolation = Isolation.SERIALIZABLE)
이런식으로 트랜잭션에 대한 세션의 독립성 보장과, COMMIT 반영 등이 중요하다.
'백엔드 > Database' 카테고리의 다른 글
| [CS/Database] DBMS에서의 B-Tree 인덱스 (0) | 2025.11.21 |
|---|---|
| [MsSQL] MsSQL의 기본 문법 (2) | 2025.10.02 |
| [Database] 친구 추가 관련 ERD 설계하기(팔로잉-팔로워) (1) | 2025.07.07 |