[CS] 트랜잭션과 동시성 제어

U·2025년 3월 21일

CS

목록 보기
5/23

📚 트랜잭션(Transaction)

트랜잭션은 데이터베이스에서 하나의 논리적인 작업 단위를 의미한다. 여러 개의 SQL 명령문이 하나의 트랜잭션으로 묶여 원자적으로 수행되며, 트랜잭션이 완전히 실행되거나 아예 실행되지 않아야 한다.

예를 들어 내가 친구에게 5만원을 송금한다고 쳐보자.

먼저 내 계좌에서 5만원이 빠져나갈 것이고 이를 친구의 계좌로 5만원을 송금한다. 이 과정에서 문제가 없을 경우 친구의 계좌에 5만원이 성공적으로 입금된다.

하지만 송금 과정에서 오류가 발생할 경우 내 계좌에서 이미 5만원은 빠져나갔지만 친구의 계좌에는 아무것도 입금되지 않는다. 결국 나의 5만원은 증발해버리는 것이다.

이러한 사태를 방지하기 위해 트랜잭션은 매우 중요하다.

ACID

트랜잭션은 ACID라는 트랜잭션이 안전하고 신뢰할 수 있도록 보장하는 4가지 필수 특성을 가진다.

1️⃣ Atomicity(원자성)

  • 트랜잭션이 모두 수행되거나 전혀 수행되지 않음을 보장

2️⃣ Consistency(일관성)

  • 트랜잭션이 성공적으로 완료되면 데이터베이스는 일관된 상태를 유지해야 함

3️⃣ Isolation(고립성)

  • 나의 트랜잭션이 실행되는 동안 다른 트랜잭션의 영향을 받지 않아야 함

4️⃣ Durability(지속성)

  • 트랜잭션이 완료된 후에는 결과가 영구적으로 반영되어야 함

📚 Commit과 Rollback

Commit

  • 트랜잭션의 작업을 데이터베이스에 영구적으로 반영하는 명령어
  • Commit이 실행되면 해당 트랜잭션이 수행한 변경 사항이 저장되며, 취소할 수 없음

Rollback

  • 트랜잭션 중 오류가 발생하거나 취소할 경우, 변경 사항을 원래 상태로 되돌리는 명령어
  • Rollback이 실행되면 해당 트랜잭션에서 수행된 모든 변경 사항이 무효화 제어

따라서 앞서 말한 상황에서, 트랜잭션은 5만원 송금에 실패할 경우 롤백을 통해 앞서 진행했던 작업인 5만원 출금을 취소하고 내 계좌에 다시 입금한다. 이로써 송금에 실패하더라도 5만원이 증발하지 않고 원래 상태로 복구된다.

이는 트랜잭션의 가장 중요한 특징인 "모든 작업이 하나의 단위로 묶여 전부 성공하든지, 아니면 전부 실패하든지 둘 중 하나만 보장한다"는 원자성을 보장한다.

Auto Commit

데이터베이스에서 SQL 문이 실행될 때 자동으로 Commit이 수행되는 기능이다. 기본적으로 Auto Commit이 활성화되어 있으며 SET AUTOCOMMIT = OFF 명령어를 사용하여 해제할 수 있다.

참고로 DDL은 자동 커밋이 되며 Rollback으로 되돌릴 수 없기 때문에, 신중하게 사용해야 한다.

트랜잭션 제어

1️⃣ 트랜잭션 시작

  • BEGIN TRANSACTION; 또는 START TRANSACTION;

2️⃣ Commit 실행

  • COMMIT;

3️⃣ Rollback 실행

  • ROLLBACK;

4️⃣ 저장점 설정 및 복구

  • SAVEPOINT 저장점이름;ROLLBACK TO 저장점이름;

📚 트랜잭션 격리 수준(Isolation Level)

여러 트랜잭션이 동시에 수행될 때, 각 트랜잭션 간에 어떤 영향을 주고받을지를 결정하는 설정

1️⃣ READ UNCOMMITTED

한 트랜잭션이 Commit하지 않은 데이터의 변경 사항을 다른 트랜잭션이 조회할 수 있으며, Dirty Read, Non-Repeatable Read, Phantom Read 문제가 발생할 수 있다.

💡 Dirty Read, Non-repeatable Read, Phantom Read란?

Dirty Read

  • 한 트랜잭션이 다른 트랜잭션이 변경 중인 데이터를 읽는 경우 발생
  • 다른 트랜잭션이 아직 커밋되지 않은 데이터를 읽은 뒤, 해당 데이터가 나중에 롤백될 경우 트랜잭션의 결과가 변경될 수 있음
  • 데이터의 일관성을 깨뜨릴 수 있음

Non-repeatable Read

  • 같은 트랜잭션 안에서 동일한 쿼리를 실행했을 때, 그 사이에 UPDATE 작업이 수행되어 다른 데이터를 얻는 경우 발생

Phantom Read

  • 한 트랜잭션이 동일한 쿼리를 두 번 실행했을 때, 두 번의 쿼리 사이에 다른 트랜잭션이 INSERT, DELETE의 작업을 수행하여 없던 데이터 행이 새로 생기거나 사라지는 경우 발생
  • 트랜잭션 내에서 일관성 없는 결과를 가져올 수 있음

2️⃣ READ COMMITTED

Commit된 데이터만 읽을 수 있으며 트랜잭션이 진행 중인 동안 다른 트랜잭션이 변경한 데이터를 볼 수 없다. Non-repeatable Read, Phantom Read 문제가 발생할 수 있다.

3️⃣ REPEATABLE READ

하나의 트랜잭션이 시작되면 특정 레코드를 같은 쿼리로 조회할 때 같은 결과를 보장한다. SERIALIZABLE과 다르게 행이 추가되는 것을 막지는 않으며, Phantom Read가 발생할 수 있다.

4️⃣ SERIALIZABLE

가장 엄격한 격리 수준으로 특정 트랜잭션이 사용중인 테이블의 모든 행을 다른 트랜잭션이 접근할 수 없도록 잠가 트랜잭션을 순차적으로 실행하는 것과 같은 효과를 보장한다. 가장 높은 데이터 정합성을 가지지만, 성능 저하가 발생할 수 있다. MySQL은 단순한 SELECT 쿼리가 실행되더라도 데이터베이스 잠금이 걸려 다른 트랜잭션에서 데이터에 접근할 수 없다.

📚 동시성 제어

다수의 사용자가 동시에 데이터베이스에 접근할 때 발생할 수 있는 문제를 방지하는 기법으로, 대표적인 동시성 제어 기법에는 3가지가 있다.

동시성 제어 기법설명
로킹 기법트랜잭션이 데이터에 잠금(Lock)을 설정하면 다른 트랜잭션은 해당 데이터에 대해 잠금이 해제(UnLock)될 때까지 접근/수정/삭제 불가
타임 스탬프 기법시스템에서 생성하는 고유 식별자인 타임 스탬프를 트랜잭션에 부여함으로써 트랜잭션 간의 접근 순서를 미리 정함
적합성 검증(낙관적)먼저 트랜잭션을 수행하고 종료할 때 적합성을 검증하여 데이터베이스에 최종 반영

갱신 손실 문제(Lost Update)

두 개 이상의 트랜잭션이 같은 데이터를 동시에 수정할 때 발생하는 문제적절한 트랜잭션 격리 수준 설정 또는 Lock 사용하면 된다.

DB 락(Lock)

트랜잭션이 데이터베이스의 특정 부분을 보호하는 메커니즘으로 두 가지가 있다.

1️⃣ 공유 락(Shared Lock, S-lock) : 읽기 작업 허용, 다른 트랜잭션의 쓰기 작업 제한
2️⃣ 베타 락(Exclusive Lock, X-lock) : 읽기와 쓰기 모두 제한

데드락(Deadlock)

두 개 이상의 트랜잭션이 서로의 자원을 점유하면서 무한 대기 상태에 빠지는 현상이다. 다음과 같은 방안으로 해결할 수 있다.

1️⃣ 트랜잭션 타임아웃 설정
2️⃣ 락 순서 준수
3️⃣ 교착 상태 회피 기법 적용

DB 회복

REDO : 재실행

  • 로그를 이용하여 시스템 장애 이후 변경된 데이터를 다시 적용하는 방식
  • Commit이 완료된 트랜잭션을 재적용하여 데이터 무결성을 유지

UNDO : 되돌리기

  • 로그를 이용하여 비정상 종료된 트랜잭션이 수행한 작업을 취소
  • Commit되지 않은 데이터를 롤백하여 일관성 유지

체크포인트 회복 기법

  • 특정 시점에서 데이터베이스 상태를 저장하여, 장애 발생 시 해당 지점에서 복구할 수 있도록 하는 방식
  • 데이터베이스의 복구 시간을 단축하는 역할을 함
profile
백엔드 개발자 연습생

0개의 댓글