MySQL에서 Lost Update 문제 해결하기: MVCC와 락킹 리드

이성혁·2024년 9월 7일

Database

목록 보기
19/24
post-thumbnail

1. Lost Update 문제란?

Lost Update는 두 개의 트랜잭션이 동일한 데이터를 동시에 수정하려 할 때, 한 트랜잭션의 변경사항이 다른 트랜잭션에 의해 덮어쓰이는 현상입니다. 이로 인해 데이터의 일관성이 깨질 수 있습니다. 예를 들어, 두 트랜잭션이 동시에 같은 계좌의 잔액을 읽고 각각 입금과 출금을 수행하면, 결과적으로 한 트랜잭션의 업데이트가 손실될 수 있습니다.

2. MySQL에서 Lost Update 문제를 해결하는 방법

예제: 기본적인 Lost Update 문제

  • 상황: 트랜잭션 1(T1)이 계좌 X의 잔액에서 40을 차감하고, 트랜잭션 2(T2)가 같은 계좌에 30을 입금한다고 가정합니다.
  • 문제: 두 트랜잭션이 동시에 실행되면, T2가 X의 잔액을 30 증가시키지만 T1이 T2의 업데이트를 덮어쓰게 되어 최종적으로 T2의 변경 사항이 사라질 수 있습니다.

이 문제를 해결하기 위해 MySQL에서는 락킹 리드(Locking Read)를 사용해야 합니다.

락킹 리드(Locking Read)란?

락킹 리드는 데이터를 읽을 때, 동시에 다른 트랜잭션이 해당 데이터를 수정하지 못하도록 락을 거는 방식입니다. MySQL에서는 SELECT ... FOR UPDATE 구문으로 이 기능을 구현할 수 있습니다. 이 구문은 데이터를 읽으면서 해당 데이터에 라이트 락을 걸어, 다른 트랜잭션이 동일 데이터를 수정하려고 할 때 대기하게 만듭니다.

SELECT balance FROM accounts WHERE id = X FOR UPDATE;

예제: 락킹 리드를 사용한 Lost Update 해결

  • 상황: 트랜잭션 2(T2)가 먼저 실행되어 X의 잔액을 30 증가시키려고 합니다. 이때 FOR UPDATE 구문을 사용하여 X의 잔액을 읽으면서 라이트 락을 획득합니다.
  • 해결: 트랜잭션 1(T1)이 X의 잔액에서 40을 차감하려고 시도할 때, T2가 이미 라이트 락을 보유하고 있어 T1은 대기 상태에 들어갑니다. T2가 완료되면 T1이 다시 실행되며, 이때 최신의 잔액을 읽고 업데이트를 수행하게 됩니다.

이 방법을 통해 T1과 T2가 서로 영향을 주지 않으면서 순차적으로 실행될 수 있으며, Lost Update 문제를 방지할 수 있습니다.

락킹 리드의 동작 방식

MySQL에서 락킹 리드는 가장 최근에 커밋된 데이터를 읽습니다. 예를 들어, T2가 30을 입금한 후 커밋하면, T1이 FOR UPDATE로 X의 잔액을 읽을 때 30이 추가된 최신 잔액을 읽게 됩니다.

SELECT balance FROM accounts WHERE id = X FOR UPDATE;

이 구문을 사용하면, T1은 T2가 커밋한 후에만 실행되어 Lost Update 문제가 발생하지 않습니다.

3. MySQL과 PostgreSQL에서의 차이점

비슷한 기능이 PostgreSQL에도 존재하지만, 두 시스템 간에는 동작 방식에 차이가 있습니다. PostgreSQL에서는 FOR UPDATE 구문을 사용하더라도 트랜잭션이 롤백될 가능성이 있습니다. 이는 PostgreSQL의 Serializable Isolation Level이 MySQL과는 달리 SSI(Serializable Snapshot Isolation) 기법을 사용하기 때문입니다. 이 기법에서는 커밋 순서에 따라 트랜잭션이 롤백될 수 있습니다.

4. 결론

MySQL에서 Lost Update 문제를 해결하기 위해서는 트랜잭션에서 FOR UPDATE 구문을 사용하여 락킹 리드를 적용하는 것이 중요합니다. 이는 데이터의 무결성을 유지하면서 동시성 문제를 해결할 수 있는 강력한 방법입니다. 또한, MySQL과 PostgreSQL 간의 동작 방식 차이를 이해하고, 이를 바탕으로 적절한 격리 수준을 선택하는 것이 필요합니다.


출처

https://www.youtube.com/watch?v=aL0XXc1yGPs&list=PLcXyemr8ZeoREWGhhZi5FZs6cvymjIBVe

profile
항상 배우는 자세로 🪴

0개의 댓글