RDBS/MYSQL

[MySQL]동시성 문제를 해결할 FOR UPDATE 알아보기

MoonSta 2023. 7. 9. 19:49

 수많은 유입이 발생하는 웹 서비스를 개발함에 있어서 동시성 문제는 가장 고려해야 할 요소 중 하나이다. 그렇기 때문에 개발을 하면서 "동시성"을 고려하여 개발을 해야 하고, 일관적 처리가 반드시 필요하다. 이번 포스팅에서는 MySQL의 동시성 문제를 처리할 수 있는 FOR UPDATE에 대해 알아보려고 한다.

 


트랜잭션(Transaction)과 락(Lock)

2023.07.02 - [분류 전체보기] - [MySQL] 트랜잭션(Trasaction) 예제로 간단하게 이해하기

 

[MySQL]트랜잭션(Trasaction) 예제로 간단하게 이해하기

트랜잭션(Transaction)이란 데이터베이스와 같은 시스템에서 처리되고 있는 업무 중 반드시 묶여서 처리되어야 하는 묶음의 최소단위이다. 일상생활에서 많이 사용되고 있는 트랜잭션 중 하나가

mooonstar.tistory.com

 

 트랜잭션은 작업의 완전성을 보장해줍니다. 논리적인 작업 셋을 모두 처리하거나, 중간에 문제 발생 시 원 상태로의 복구를 시켜줍니다  즉,  트랜잭션은 데이터의 정합성을 보장합니다.

 

 반면에 테이블 잠금(Lock)은 트랜잭션과 비슷한 내용같지만 동시성 제어를 하기 위한 기능입니다. 잠금(Lock)을 하게 되면 여러 세션이 동시에 동일한 처리를 하게 되어 테이블에 변경이 일어나는 경우 가장 처음 접근했던 세션이 끝날 때까지 다른 세션을 잠금하여 한 건씩 처리할 수 있게 해 줍니다. 

 


 

MySQL의 FOR UPDATE문 알아보기

 

 MySQL의 FOR UPDATE문을 사용하면 조회 된 ROW에 대해 COMMIT 이전까지 해당 데이터의 CRUD를 모두 차단할 수 있습니다. 

 

START TRANSACTION;
SELECT * FROM TABLE WHERE ID = 1 FOR UPDATE;
COMMIT;

 

즉, 위의 쿼리와 같이 COMMIT이 실행되기 전까지 ID가 1인 데이터에 대해 다른 CRUD가 모두 차단되는 것입니다.  하지만 다른 세션에서 동시에 접근하게 된다면 어떻게 될까요?

 

#세션 : A
SELECT * FROM TABLE WHERE ID = 1 FOR UPDATE;

#세션 : B
SELECT * FROM TABLE WHERE ID = 1 FOR UPDATE;

#세션 : C
SELECT * FROM TABLE WHERE ID = 1 FOR UPDATE;

 

 거의 동시에 3개의 세션에서 ID가 1인 데이터의 CRUD가 발생할 때 세션 A가 LOCK을 획득하게 됩니다. 이후 세션 A의 COMMIT이 진행되고 나서야 순차적으로 B, C가 실행되며 동시성 문제를 해결할 수 있습니다.

 

#세션 : A
SELECT * FROM TABLE WHERE ID = 1 FOR UPDATE;

#세션 : B
SELECT * FROM TABLE WHERE ID = 1 FOR UPDATE;

#세션 : C
SELECT * FROM TABLE WHERE ID = 2 FOR UPDATE;

 

 위와 같이 세션 A와 B가 ID가 1인 데이터에 접근하고 세션 C는 ID가 2인 데이터에 접근한다고 가정하면 A가 접근하는 동안 세션 B는 세션A가 COMMIT이 완료되는 시점까지 WAITING 상태를 유지합니다. 하지만 세션C는 다른 ROW에 접근하기 때문에 WAITING 상태없이 실행됩니다.