데이터베이스 잠금으로 동시 트랜잭션을 제어하는 법

데이터베이스 잠금의 공유·배타적 잠금, 호환성, 잠금 단위와 교착 상태를 정리하고 트랜잭션 성능 전략을 설명합니다.

2026-08-14 · 최초 발행 2025-08-10

같은 데이터를 동시에 다룰 때 잠금이 맡는 역할

트랜잭션이 같은 데이터 항목을 동시에 읽거나 변경하면 결과의 일관성이 흔들릴 수 있다. 잠금(Lock)은 데이터 항목에 상호 배제(Mutual Exclusion)를 적용해 트랜잭션 사이의 접근을 조정하는 동시성 제어 기법이다.

트랜잭션은 데이터에 접근하면서 잠금을 설정하고, 다른 트랜잭션은 그 잠금 상태에 따라 접근하거나 대기한다. 이 제어가 데이터 무결성과 데이터베이스 신뢰성의 기반이 된다.

읽기와 변경에 사용하는 잠금

공유 잠금(Shared Lock, S-Lock)은 읽기 전용 잠금이다. 잠금을 보유한 트랜잭션은 데이터 항목을 읽을 수 있지만 수정할 수 없으며, 여러 트랜잭션이 같은 항목에 공유 잠금을 동시에 설정할 수 있다. 조회(SELECT)에 활용된다.

-- 공유 잠금 예시(MySQL)
SELECT * FROM customers WHERE customer_id = 100 LOCK IN SHARE MODE;

배타적 잠금(Exclusive Lock, X-Lock)은 읽기와 쓰기를 모두 허용한다. 한 트랜잭션이 X-Lock을 설정한 데이터에는 다른 트랜잭션이 접근할 수 없고, S-Lock과 X-Lock 어느 쪽과도 호환되지 않는다. 수정(UPDATE), 삭제(DELETE), 삽입(INSERT) 작업에서 사용된다.

-- 배타적 잠금 예시(MySQL)
SELECT * FROM customers WHERE customer_id = 100 FOR UPDATE;

잠금 요청과 기존 보유 잠금의 관계는 다음과 같다.

요청/보유 S-Lock X-Lock
S-Lock 허용 대기
X-Lock 대기 대기
S-Lock 요청S-Lock 요청X-Lock 요청트랜잭션 A데이터 항목트랜잭션 B트랜잭션 CS-Lock: 허용X-Lock: 대기

잠금 범위가 바꾸는 동시성과 비용

잠금은 행, 테이블, 페이지처럼 서로 다른 단위에 적용할 수 있다. 단위가 작을수록 다른 데이터에 대한 접근을 더 허용하지만, 잠금을 관리하는 오버헤드는 커진다.

행 수준 잠금(Row-level Lock)은 개별 데이터 행을 잠근다. 높은 동시성을 제공하고 다른 행에 대한 접근을 허용하므로, 높은 동시성이 필요한 OLTP(Online Transaction Processing) 시스템에 적합하다. 반면 잠금 관리 오버헤드는 증가한다.

테이블 수준 잠금(Table-level Lock)은 테이블 전체를 대상으로 한다. 잠금 관리 오버헤드는 줄어들지만 동시성과 병렬 처리가 제한된다. 대량 데이터 처리나 스키마 변경 작업에서 활용된다.

페이지 수준 잠금(Page-level Lock)은 데이터베이스 페이지 단위로 잠금을 설정한다. 행 수준과 테이블 수준의 중간 정도 동시성과 오버헤드를 제공하며, 일부 DBMS는 성능 최적화를 위해 이 방식을 사용한다.

잠금 단위 계층 구조데이터베이스테이블페이지컬럼동시성 증가오버헤드 증가동시성 감소오버헤드 감소

대기 상태가 길어질 때 발생하는 문제

교착 상태(Deadlock)는 둘 이상의 트랜잭션이 서로 상대방이 보유한 잠금을 기다려 어느 쪽도 진행하지 못하는 상태다. DBMS의 교착 상태 감지 및 해소 알고리즘, 타임아웃 설정, 트랜잭션 롤백으로 대응한다.

X-Lock on 데이터1S-Lock 요청 on 데이터2X-Lock on 데이터2S-Lock 요청 on 데이터1트랜잭션 A데이터1데이터2트랜잭션 B교착 상태 발생

라이브록(Livelock)은 트랜잭션들이 계속 서로에게 양보하지만 실제 작업은 진행하지 못하는 경우다. 백오프 시간을 조정하거나 우선순위를 부여해 완화할 수 있다.

연쇄 대기(Cascading Wait)는 한 트랜잭션의 대기가 다른 트랜잭션들의 대기로 이어지는 현상이다. 잠금 요청 순서를 조정하고 잠금 에스컬레이션 전략을 적용하는 방법이 있다.

재고와 계좌 이체에서의 잠금 사용

온라인 쇼핑몰에서 재고를 조회할 때는 S-Lock을, 재고를 줄일 때는 X-Lock을 적용할 수 있다.

-- 상품 재고 조회 (S-Lock)
BEGIN TRANSACTION;
SELECT stock FROM products WHERE product_id = 100 LOCK IN SHARE MODE;
-- 다른 조회 작업 수행 가능
COMMIT;

-- 재고 감소 (X-Lock)
BEGIN TRANSACTION;
SELECT stock FROM products WHERE product_id = 100 FOR UPDATE;
UPDATE products SET stock = stock - 1 WHERE product_id = 100;
COMMIT;

계좌 이체는 출금 계좌와 입금 계좌 모두에 X-Lock을 설정한 뒤 잔액 검증과 변경을 같은 트랜잭션 안에서 처리한다.

-- 계좌 이체 트랜잭션
BEGIN TRANSACTION;
-- 출금 계좌 잠금 (X-Lock)
SELECT balance FROM accounts WHERE account_id = 1001 FOR UPDATE;
-- 입금 계좌 잠금 (X-Lock)
SELECT balance FROM accounts WHERE account_id = 2002 FOR UPDATE;

-- 잔액 검증 및 이체 작업
UPDATE accounts SET balance = balance - 1000 WHERE account_id = 1001;
UPDATE accounts SET balance = balance + 1000 WHERE account_id = 2002;
COMMIT;

DBMS가 제공하는 잠금 방식

Oracle Database는 Shared, Exclusive, Row Share, Row Exclusive, Share Row Exclusive 등 다양한 잠금 모드를 지원하며, 다중 버전 동시성 제어(MVCC) 방식과 결합된 잠금 메커니즘을 사용한다.

MySQL/InnoDB는 공유(S), 배타적(X), 의도 공유(IS), 의도 배타적(IX) 잠금을 지원한다. 레코드 잠금, 갭 잠금, 넥스트 키 잠금 등 세부 잠금 기법도 제공한다.

SQL Server는 Shared, Exclusive, Update, Intent, Schema 등 여러 잠금 유형을 제공하며, 낙관적 동시성 제어와 비관적 동시성 제어를 모두 지원한다.

경합을 줄이는 트랜잭션 설계

잠금 유지 시간을 줄이려면 트랜잭션 실행 시간을 최소화하고, 불필요한 연산은 트랜잭션 외부로 옮긴다.

여러 자원에 접근하는 트랜잭션은 같은 순서를 따르도록 설계해야 한다. 일관된 잠금 획득 순서는 교착 상태 방지에 효과적이다.

인덱스는 잠금 대상 행의 수를 줄이는 데도 영향을 준다. 테이블 스캔 대신 인덱스 접근을 활용하도록 설계한다. 격리 수준 역시 요구사항에 맞춰 선택하며, READ COMMITTED나 READ UNCOMMITTED를 사용하면 일부 상황에서 잠금을 줄일 수 있다.

데이터베이스잠금동시성 제어트랜잭션교착 상태DBMS