트랜잭션?

일련의 작업들을 하나의 단위로 묶어서 처리하는 것을 의미한다. ACID 속성을 지켜야 하는데 의미는 다음과 같다. 

ACID 속성

  1. 원자성(Atomicity)
    • 트랜잭션의 작업들이 모두 성공적으로 완료되거나, 모두 실패하여 아무런 변화도 일어나지 않도록 보장한다. 중간 상태는 존재하지 않는다.
  2. 일관성(Consistency)
    • 트랜잭션이 실행되기 전과 후의 데이터베이스 상태가 일관성을 유지해야 한다. 즉, 트랜잭션이 성공적으로 완료되면 데이터베이스는 항상 일관된 상태로 유지되어야 한다.
  3. 격리성(Isolation)
    • 동시에 실행되는 트랜잭션들이 서로의 작업에 영향을 미치지 않도록 보장한다. 하나의 트랜잭션이 완료될 때까지 다른 트랜잭션이 그 결과를 볼 수 없다.
  4. 지속성(Durability)
    • 트랜잭션이 성공적으로 완료되면, 그 결과는 영구적으로 저장되어야 한다. 시스템 장애가 발생하더라도 결과는 손실되지 않는다.

트랜잭션을 고려하는 과정에서  계좌 이체 대상에 문제가 생겼는데 강제로 커밋한다면? 어떻게 될까? 
이런 상황에서는 롤백을 호출해서 트랜잭션 시작 시점으로 돌려놔야 한다. 

예를 들어서 롤백은 다음과 같이 처리할 수 있다.

BEGIN TRANSACTION;

-- 계좌 A에서 100달러 출금
UPDATE accounts SET balance = balance - 100 WHERE account_id = 'A';

-- 계좌 B에 100달러 입금
UPDATE accounts SET balance = balance + 100 WHERE account_id = 'B';

IF @@ERROR -- 만약 오류가 발생하면
BEGIN
    ROLLBACK; -- 트랜잭션을 롤백하여 모든 변경을 취소
END
ELSE
BEGIN
    COMMIT; -- 트랜잭션을 커밋하여 변경을 영구적으로 적용
END

트랜잭션의 원자성이 깨지는 경우는 세션1이 트랜잭션을 시작하고 데이터를 수정하는 동안 커밋을 수행하지 않았는데 세션2에서 동시에 같은 데이터를 수정하게 되는 케이스. 그래서 커밋이나 롤백 전까지 다른 세션에서 해당 데이터를 수정할 수 없게 막아야 한다. 

동시성 제어와 트랜잭션 격리

데이터베이스는 여러 사용자가 동시에 데이터에 접근하고 수정할 수 있는 환경에서 동시성 제어를 통해 데이터의 무결성을 유지한다.

  1. Read Uncommitted: 트랜잭션이 커밋되지 않은 데이터를 다른 트랜잭션이 읽을 수 있다. 가장 낮은 격리 수준으로, '더러운 읽기(Dirty Read)'가 발생할 수 있다.
  2. Read Committed: 트랜잭션이 커밋된 데이터만 다른 트랜잭션이 읽을 수 있다. '더러운 읽기'는 방지되지만, '비반복 읽기(Non-repeatable Read)'는 발생할 수 있다.
  3. Repeatable Read: 트랜잭션 동안 동일한 데이터를 여러 번 읽을 때 항상 동일한 결과를 보장한다. '비반복 읽기'는 방지되지만, '팬텀 읽기(Phantom Read)'가 발생할 수 있다.
  4. Serializable: 가장 높은 격리 수준으로, 트랜잭션을 직렬화하여 실행하여 모든 동시성 문제를 방지한다. '팬텀 읽기'도 방지된다.

잠금 메커니즘

트랜잭션 격리 수준을 구현하기 위해 데이터베이스는 다양한 잠금 메커니즘을 사용한다. 잠금은 특정 리소스(예: 행, 테이블)를 다른 트랜잭션이 접근하지 못하도록 하는 방법이다.

  • 공유 잠금(Shared Lock, S): 데이터를 읽기 위한 잠금으로, 다른 트랜잭션도 읽기 잠금을 걸 수 있지만, 쓰기 잠금은 걸 수 없다.
  • 배타적 잠금(Exclusive Lock, X): 데이터를 수정하기 위한 잠금으로, 다른 트랜잭션이 읽기나 쓰기 잠금을 걸 수 없다.

동시에 데이터를 수정하는 경우는 Lock을 어떻게 수행되는지 보자. 보통 lock을 획득해야 데이터를 변경할 수 있다. 

트랜잭션 반영하기 전에 조회는 가능하다. 데이터를 조회하는데 lock을 획득하고 싶을 때가 있다. 조회를 하고 어떤 복잡한 비즈니스 연산을 하는게 해당 케이스가 되겠다. select ~ for update 구문을 사용한다. 

잠금 반납의 중요성

트랜잭션이 완료되면 잠금은 자동으로 반납된다. 이는 데이터베이스에서 필수적인 동작이다. 왜냐하면 잠금을 오랜 시간 유지하면 다음과 같은 문제가 발생할 수 있기 때문이다:

  • 동시성 저하: 다른 트랜잭션이 해당 데이터에 접근하지 못해 대기 시간이 길어집니다.
  • 교착 상태(Deadlock): 여러 트랜잭션이 서로 다른 자원을 기다리면서 무한히 대기하게 되는 상황이 발생할 수 있습니다.

트랜잭션은 공통적으로 lock이 반납된다. 

 

'IT' 카테고리의 다른 글

zipkin  (2) 2024.07.01
스프링 클라우드 슬루스와 집킨 정리  (0) 2024.06.30
resilience 4j 발표 내용 정리  (0) 2024.04.21
몽고디비 11장 - 복제 셋 구성요소  (0) 2024.04.14
몽고 디비 9장  (0) 2024.04.01