DB

[MySQL] SELECT FOR UPDATE 완벽 가이드 – 동시성 제어의 핵심 키워드

인생아 2025. 6. 30. 10:11
반응형

트랜잭션(Transaction) 환경에서 데이터 정합성을 유지하고자 할 때, 꼭 알아야 하는 기능이 있습니다. 바로 SELECT FOR UPDATE입니다.
이 구문은 동시에 여러 사용자가 같은 데이터를 조작할 수 없도록 레코드에 잠금(Lock)을 거는 기능으로, MySQL InnoDB 엔진을 사용할 때 매우 중요하게 작동합니다.

✅ SELECT FOR UPDATE란?

SELECT FOR UPDATE는 트랜잭션 내에서만 사용 가능한 SELECT 문으로, 조회된 행(row)에 대해 쓰기 잠금(Write Lock)을 겁니다.
다른 세션은 해당 행을 수정하거나 삭제할 수 없고, 잠금이 풀릴 때까지 대기하게 됩니다.

기본 문법

START TRANSACTION;

SELECT * FROM users WHERE id = 1 FOR UPDATE;

-- 이후 UPDATE or DELETE 실행 가능

COMMIT;
반응형

✅ 왜 필요한가? – 데이터 정합성 보장

동시에 여러 유저가 하나의 데이터를 조작할 때, 잘못하면 다음과 같은 문제가 생길 수 있습니다:

  • 중복 처리
  • 경합 조건(Race Condition)
  • 정합성 깨짐

SELECT FOR UPDATE를 사용하면 트랜잭션이 끝나기 전까지 행을 보호하여 위와 같은 문제를 방지할 수 있습니다.

✅ 실전 예제 1: 은행 이체 처리

START TRANSACTION;

-- 송신자 계좌 잠금
SELECT balance FROM accounts WHERE user_id = 1 FOR UPDATE;

-- 수신자 계좌 잠금
SELECT balance FROM accounts WHERE user_id = 2 FOR UPDATE;

-- 금액 차감 및 이체
UPDATE accounts SET balance = balance - 10000 WHERE user_id = 1;
UPDATE accounts SET balance = balance + 10000 WHERE user_id = 2;

COMMIT;

🔍 설명: 두 계좌의 금액을 안전하게 처리하기 위해 SELECT FOR UPDATE로 먼저 락을 걸고, 이후 UPDATE 실행 → COMMIT으로 적용

✅ 실전 예제 2: 재고 감소 처리 (쇼핑몰)

START TRANSACTION;

SELECT stock
FROM products
WHERE product_id = 1001
FOR UPDATE;

UPDATE products
SET stock = stock - 1
WHERE product_id = 1001;

COMMIT;

🔍 설명: 동시에 수많은 사용자가 구매 요청을 보낼 때 재고가 음수가 되는 것을 방지할 수 있음

반응형

✅ SELECT FOR UPDATE 주의사항

항목 설명
🔒 사용 가능한 스토리지 엔진 InnoDB (MyISAM은 미지원)
🔄 반드시 트랜잭션 내에서 사용 START TRANSACTION 없이 실행 시 무효
🔍 WHERE 조건 필수 불필요한 테이블 전체 락 방지
⚠️ 인덱스 없는 컬럼은 범위 잠금이 불안정 가능하면 인덱스를 활용하자
 

❗ 잠금이 해제되는 시점은 언제?

  • COMMIT 또는 ROLLBACK 시점에 잠금이 해제됩니다.

✅ SELECT FOR UPDATE vs LOCK IN SHARE MODE

항목 SELECT FOR UPDATE LOCK IN SHARE MODE
잠금 유형 쓰기 잠금 (X Lock) 공유 잠금 (S Lock)
다른 세션의 읽기 허용 ❌ 불가능 (잠금 대기) ✅ 가능
쓰기 가능 여부 ✅ 가능 ❌ 불가능
사용 목적 수정/삭제 목적의 조회 단순 조회, 정합성 보장 목적
 

✅ 성능과 동시성 팁

  • 짧은 트랜잭션이 핵심입니다. 트랜잭션이 길어지면 대기하는 세션이 많아져 전체 성능이 저하됩니다.
  • WHERE 절로 명확한 조건 지정 → 불필요한 레코드에 락을 걸지 않도록
  • 트랜잭션 중에는 가능한 최소한의 쿼리만 수행하세요.

✅ 공식 가이드 문서 참고

 

반응형