MySQL 트랜잭션의 이해와 활용

START TRANSACTION;

-- 출금
UPDATE accounts SET balance = balance - 100 WHERE user_id = 1;

-- 입금
UPDATE accounts SET balance = balance + 100 WHERE user_id = 2;

COMMIT;

MySQL에서 트랜잭션(Transaction)은 데이터베이스의 작업을 하나의 단위로 묶어주는 중요한 개념입니다. 트랜잭션을 사용하면 데이터베이스에서 발생하는 여러 작업을 원자성(Atomicity), 일관성(Consistency), 격리성(Isolation), 지속성(Durability)을 보장하면서 처리할 수 있습니다. 이 글에서는 MySQL 트랜잭션의 기본 개념을 이해하고, 실제로 어떻게 활용할 수 있는지 예시를 통해 알아보겠습니다.

 

1. 트랜잭션이란?

트랜잭션은 하나 이상의 SQL 작업을 하나의 논리적인 작업 단위로 묶은 것입니다. 트랜잭션 내의 작업은 모두 성공적으로 완료되거나, 모두 취소되어야 하며, 중간에 문제가 발생하면 모든 작업이 원래 상태로 되돌려집니다.

트랜잭션의 ACID 속성:

  • Atomicity(원자성): 트랜잭션 내의 모든 작업은 하나로 묶여 실행되며, 일부 작업만 수행되고 나머지는 취소될 수 없습니다.
  • Consistency(일관성): 트랜잭션이 완료되면 데이터베이스가 일관된 상태를 유지해야 합니다.
  • Isolation(격리성): 트랜잭션은 다른 트랜잭션에 의해 영향을 받지 않도록 독립적으로 실행됩니다.
  • Durability(지속성): 트랜잭션이 완료되면 그 결과는 영구적으로 저장되며, 시스템 장애가 발생해도 데이터는 손실되지 않습니다.

2. 트랜잭션 시작과 종료

MySQL에서 트랜잭션을 사용하려면, START TRANSACTION 명령어로 트랜잭션을 시작하고, COMMIT으로 트랜잭션을 완료합니다. 만약 트랜잭션 중 오류가 발생하면 ROLLBACK을 사용하여 트랜잭션을 취소할 수 있습니다.

예시:

START TRANSACTION;  -- 트랜잭션 시작

UPDATE accounts SET balance = balance - 100 WHERE user_id = 1;  -- 사용자 1에게 100만큼 차감
UPDATE accounts SET balance = balance + 100 WHERE user_id = 2;  -- 사용자 2에게 100만큼 추가

COMMIT;  -- 트랜잭션 완료

위 예시에서 accounts 테이블의 사용자 1에서 100원을 차감하고, 사용자 2에게 100원을 추가하는 작업을 트랜잭션 내에서 묶었습니다. 두 작업이 모두 성공해야만 COMMIT을 통해 결과가 반영됩니다.

 

3. 트랜잭션 취소(Rollback)

트랜잭션 중 오류가 발생하거나 취소하고 싶을 경우, ROLLBACK 명령어를 사용하여 트랜잭션을 취소할 수 있습니다. ROLLBACK을 실행하면, 트랜잭션 시작 이전 상태로 되돌아갑니다.

예시:

START TRANSACTION;

UPDATE accounts SET balance = balance - 100 WHERE user_id = 1;  -- 사용자 1에게 100만큼 차감
UPDATE accounts SET balance = balance + 100 WHERE user_id = 2;  -- 사용자 2에게 100만큼 추가

-- 오류 발생 시 트랜잭션 취소
ROLLBACK;

위 쿼리에서 오류가 발생하면 ROLLBACK을 사용하여 두 작업 모두 취소하고 데이터베이스는 이전 상태로 복구됩니다.

 

4. 트랜잭션 격리 수준 (Isolation Level)

트랜잭션의 격리성을 설정하는 것은 매우 중요합니다. MySQL은 트랜잭션 격리 수준을 설정하여 다른 트랜잭션이 데이터에 접근하는 방식을 제어할 수 있습니다. MySQL은 4가지 격리 수준을 제공합니다:

  • READ UNCOMMITTED: 다른 트랜잭션이 아직 커밋되지 않은 데이터를 읽을 수 있습니다.
  • READ COMMITTED: 다른 트랜잭션이 커밋한 데이터만 읽을 수 있습니다.
  • REPEATABLE READ: 트랜잭션 시작 시점에 읽은 데이터를 계속 읽을 수 있습니다.
  • SERIALIZABLE: 가장 높은 격리 수준으로, 트랜잭션이 직렬화되어 실행됩니다.

예시:

SET TRANSACTION ISOLATION LEVEL REPEATABLE READ;
START TRANSACTION;

격리 수준을 설정하면, 데이터가 어떻게 읽히고 쓰여지는지 제어할 수 있어, 여러 트랜잭션이 동시에 실행될 때 발생할 수 있는 문제들을 해결할 수 있습니다.

 

5. 트랜잭션 활용 예시

트랜잭션은 주로 데이터의 일관성을 보장해야 할 때 사용됩니다. 예를 들어, 은행 계좌 이체와 같은 작업은 트랜잭션을 사용해야 합니다. 두 계좌의 잔액을 변경하는 작업은 모두 성공하거나 모두 실패해야 하기 때문에 트랜잭션을 사용해야 합니다.

예시: 은행 계좌 이체

 

위 예시에서 출금과 입금 작업은 트랜잭션 내에서 처리되며, 두 작업이 모두 성공해야만 COMMIT을 통해 결과가 적용됩니다. 중간에 오류가 발생하면 ROLLBACK을 사용하여 모든 변경을 취소할 수 있습니다.

 

6. 트랜잭션과 록(Lock)

트랜잭션을 사용하면 **데이터의 잠금(Lock)**을 설정할 수 있습니다. 이는 동시에 여러 트랜잭션이 동일한 데이터에 접근할 때 발생할 수 있는 문제를 방지하는 데 도움이 됩니다.

  • 공유 잠금 (Shared Lock): 다른 트랜잭션이 데이터를 읽을 수는 있지만, 수정은 할 수 없습니다.
  • 배타적 잠금 (Exclusive Lock): 다른 트랜잭션이 데이터를 읽거나 수정할 수 없습니다.

예시:

SELECT * FROM accounts WHERE user_id = 1 FOR UPDATE;

위 쿼리는 user_id = 1인 행에 대해 배타적 잠금을 설정합니다. 이로 인해 다른 트랜잭션은 이 행을 수정할 수 없습니다.

 

마무리

MySQL 트랜잭션은 데이터의 원자성, 일관성, 격리성, 지속성을 보장하여 데이터베이스의 신뢰성과 안정성을 높이는 중요한 기능입니다. 트랜잭션을 적절히 활용하면, 특히 여러 작업을 하나의 단위로 묶을 때 데이터의 무결성을 유지할 수 있습니다. 또한, 격리 수준을 설정하여 트랜잭션 간의 간섭을 최소화하고, 잠금을 통해 동시성 문제를 방지할 수 있습니다.