본문 바로가기
Backend/Mysql

[MySQL] Deadlock(교착 상태) 원인

by 제이동 개발자 2024. 10. 27.
728x90

Deadlock(교착 상태) 원인

 MySQL에서 Deadlock(교착 상태)는 두 개 이상의 트랜잭션이 서로가 필요로 하는 자원을 서로 잠금하고 있어 두 개 트랜잭션이 모두 완료하지 못하고 Rollback(롤백)이 되는 상태를 말한다. 일반적으로 Deadlock은 여러 트랜잭션이 동시에 데이터베이스 자원(행, 테이블 등)을 접근할 때 발생할 수 있으며 발생되는 원인에 대해 알아보자.

 

1. 교차 락(Cross Locking)

 두 개 이상의 트랜잭션이 서로의 필요로 하는 자원을 잠그고, 상대방이 소유한 락을 기다리며 발생하는 상황이다.

  • 트랜잭션 A가 id = 1인 행을 배타적 락을 건다.
  • 트랜잭션 B가 id = 2인 행을 배타적 락을 건다.
  • 트랜잭션 A가 id = 2인 행을 배타적 락을 걸기 위해 트랜잭션 B가 걸었던 id = 2인 행의 배타적 락이 끝날 때까지 기다린다.
  •  트랜잭션 B가 id = 1인 행을 배타적 락을 걸기 위해 트랜잭션 A가 걸었던 id = 1인 행의 배타적 락이 끝날 때까지 기다린다.
-- 트랜잭션 A
BEGIN;
UPDATE orders SET status = 'processed' WHERE id = 1;  -- 행 1 잠금
-- 트랜잭션 B가 실행되기 전까지 기다림
UPDATE orders SET status = 'processed' WHERE id = 2;  -- 행 2 요청

-- 트랜잭션 B
BEGIN;
UPDATE orders SET status = 'processed' WHERE id = 2;  -- 행 2 잠금
-- 트랜잭션 A가 실행되기 전까지 기다림
UPDATE orders SET status = 'processed' WHERE id = 1;  -- 행 1 요청

 

 

2. 다중 트랜잭션에서 동일한 순서가 아닌 자원 잠금

 여러 트랜잭션이 동일한 테이블이나 행을 접근할 때 접근 순서가 다를 경우 발생할 수 있다.

  • 트랜잭션 A가 accounts 테이블의 user_id = 1인 행을 배타적 락을 건다.
  • 트랜잭션 B가 transactions 테이블의 transaction_id= 123인 행을 배타적 락을 건다.
  • 트랜잭션 A가 transactions 테이블의 transaction_id= 123인 행을 배타적 락을 걸기 위해 트랜잭션 B가 걸었던 transaction_id= 123인 행의 배타적 락이 끝날 때까지 기다린다.
  •  트랜잭션 B가 accounts 테이블의 user_id = 1인 행을 배타적 락을 걸기 위해 트랜잭션 A가 걸었던 user_id = 1인 행의 배타적 락이 끝날 때까지 기다린다.
-- 트랜잭션 A
BEGIN;
UPDATE accounts SET balance = balance - 100 WHERE user_id = 1;
-- 트랜잭션 B가 실행되기 전까지 기다림
UPDATE transactions SET status = 'completed' WHERE transaction_id = 123;

-- 트랜잭션 B
BEGIN;
UPDATE transactions SET status = 'processing' WHERE transaction_id = 123;
-- 트랜잭션 A가 실행되기 전까지 기다림
UPDATE accounts SET balance = balance + 100 WHERE user_id = 1;

 

 

3. 다중 업데이트 하는 경우

 다중 업데이트를 하는 경우 MySQL은 테이블을 풀 스캔하며 레코드를 잠그게 되는데 동시에 여러 트랜잭션이 테이블의 잠금 요청을 하면 Deadlock이 발생하게 된다.

 아래는 두 트랜잭션이 인덱스 없이 같은 테이블에서 범위 업데이트를 수행할 때 발생하는 케이스이다.

-- 트랜잭션 A
BEGIN;
UPDATE products SET stock = stock - 1 WHERE category = 'electronics';  -- 인덱스 없는 카테고리 업데이트
-- 트랜잭션 B가 실행되기 전까지 기다림

-- 트랜잭션 B
BEGIN;
UPDATE products SET stock = stock + 1 WHERE category = 'electronics';  -- 동일한 조건의 인덱스 없는 업데이트

 

 

4. 외래 키 제약 조건

 외래 키로 연결된 테이블에서 트랜잭션이 서로 연관된 데이터를 업데이트하거나 삭제할 때 Deadlock이 발생할 수 있다. 

-- 트랜잭션 A
BEGIN;
DELETE FROM customers WHERE id = 1;  -- 부모 테이블에서 삭제
-- 트랜잭션 B가 실행되기 전까지 기다림

-- 트랜잭션 B
BEGIN;
INSERT INTO orders (customer_id, amount) VALUES (1, 100);  -- 자식 테이블에 외래 키로 연결된 데이터 삽입

 

 

728x90

'Backend > Mysql' 카테고리의 다른 글

[MySQL] MySQL 설치 후 Database 생성하기  (0) 2025.04.05
[Mysql] Lock Type  (1) 2024.10.27
[MySQL] index 생성 시 고려할 점  (0) 2024.10.20