<SQL BOOSTER>의 내용을 바탕으로 작성된 개인 공부를 위한 기록용 포스트입니다.
들어가기 전에
트랜잭션은 반드시 한 번에 처리되어야 하는 논리적인 작업 단위다. 만약 계좌이체를 하는데 출금한 계좌에서는 돈이 빠져나갔는데, 입급되어야 하는 계좌에 돈이 안 들어온다면 어떻게 될까? 바로 이렇게 절대 분리해서 실행할 수 없는 작업의 최소 단위를 트랜잭션이라고 한다.
만약 두 과정 중에 문제가 생긴다면 트랜잭션을 ROLLBACK하여 데이터를 트랜잭션 시작 이전 상태로 되돌린다. SQL에서 발생한 에러는 예외 처리를 통해서 쉽게 ROLLBACK 할 수 있지만, 예를 들어 입금하려는 계좌가 아예 존재하는 않는다는 등의 문제가 발생하면 출금하는 계좌에서는 이미 금액이 차감되어있는 실수가 일어날 수 있으니 점검 로직을 추가해서 반드시 트랜잭션을 ROLLBACK해야 한다.
COMMIT이 잘못 수행된 경우에도 에러가 발생한 문장 하나만 ROLLBACK이 될 수 있기 때문에 명시적으로 ROLLBACK을 실행해서 트랜잭션 전체를 되돌려야 한다. 그리고 외부 API를 사용하는 로직이 섞여있다면 외부 API를 호출하는 전후의 SQL문은 ROLLBACK이 되지만 실제 외부에서 수행됐던 로직은 ROLLBACK되지 않기 때문에 주의해야 한다.
그렇다면 트랜잭션은 언제 시작되고 언제 끝맺음을 하는 걸까? 트랜잭션은 데이터 변경 SQL이 실행되는 순간 시작되어 COMMIT이나 ROLLBACK을 만나기 전까지 유지된다. 그러니까 모두 반영하거나(COMMIT), 모두 반영하지 않거나(ROLLBACK)로 끝이 나게 된다.
트랜잭션 테스트
테스트를 위해 간단한 계좌 테이블을 만들고 계좌 번호와 이름, 그리고 금액까지 세 개의 컬럼을 가지고 있게 했다. 현재 계좌 테이블에는 ACC1, ACC2, ACC3 계좌가 준비되어있다. ACC1에서 ACC2로 계좌 이체를 한다면 아무 문제없이 정상적으로 수행된다. 하지만 만약 존재하지 않는 계좌로 이체를 한다면 어떨까?
UPDATE m_acc T1
SET T1.bal_amt = T1.bal_amt - 500
WHERE T1.acc_no = 'ACC1';
UPDATE m_acc T1
SET T1.bal_amt = T1.bal_amt + 500
WHERE T1.acc_no = 'ACC4';
아무런 에러가 발생하지 않은 채로 ACC1 계좌에서만 500원이 빠져나간다. 이런 상황일 때 ROLLBACK으로 데이터를 이전 상태로 되돌려야 한다.
ROLLBACK을 하고 나면 ACC1 계좌에서 빠져나갔던 500원이 다시 돌아와 2500원이 있어야 한다.
ROLLBACK;
하지만 2500원으로 돌아오지 않는다면 무엇이 문제일까? 이때는 AUTO COMMIT 설정을 보면 된다. AUTO COMMIT 설정값이 true로 되어있으면 false로 변경해주자.
MySQL에서 AUTO COMMIT은 아래와 같이 설정값을 확인하고 변경해주면 된다. 그리고 위의 테스트를 다시 진행하면 ROLLBACK이 수행되는 것을 확인할 수 있다.
SELECT @@AUTOCOMMIT;
SET AUTOCOMMIT = false;
COMMIT;
참고로 MySQL의 InnoDB는 AUTO COMMIT이 활성화되어있고 각각의 SQL문에서 에러가 발생하지 않으면 자동으로 COMMIT을 해준다. 하나의 변경이 일어날 때마다 COMMIT을 계속 해주게 되면 디스크에 있는 로그 파일에 변경 내역을 계속해서 저장해야 하기 때문에 IO 작업량이 많아져 성능에 문제가 생길 수 있다.
ROLLBACK 또한 많은 작업 이후에 수행하게 되면 성능이 저하되므로 변경 작업을 할 때 분리하는 것도 방법이고 그 사이사이에 COMMIT을 해줄 수도 있다.
정리
- 트랜잭션은 한 번에 이루어져야 하는 작업 단위다.
- 트랜잭션은 COMMIT이나 ROLLBACK으로 종료가 이루어진다.
- COMMIT으로 종료될 경우, 트랜잭션에서 변경된 데이터들은 모두 DB에 실제 반영된다.
- ROLLBACK으로 종료될 경우, 트랜잭션 시작 이전으로 데이터들은 복구가 된다.
참고
'DB' 카테고리의 다른 글
[DB] Lock (0) | 2023.03.08 |
---|---|
[DB] 트랜잭션(2) - Isolation Level (0) | 2023.03.07 |
[MySQL] 복합 인덱스의 성능을 위한 순서 최적화 (0) | 2023.03.05 |
[DB] DBMS의 commit과 rollback은 어떻게 처리되는가 (0) | 2023.01.26 |
[MySQL] 실행계획 알아보기 (1) | 2023.01.24 |