트랜잭션 격리(Isolation) (1)

jYur·2022년 8월 11일
0

트랜잭션을 하나하나 줄 세워서 처리하면 느리기 때문에 그렇게 보통 그렇게 안 해.
그러다 보니 "동시성 문제"가 발생하고 그걸 해결하기 위한 방법이 트랜잭션 격리야.

첫 번째 트랜잭션이 커밋되기 전에
두 번째 트랜잭션이 시작된다면
두 트랜잭션은 동시적이라고 간주
- aws

0. 격리 수준

low
1. Read Uncommitted
2. Read Committed
3. Repeatable Read
4. Serializable
high

1. Read Uncommitted

격리를 안 하는 수준
; 읽을 때, 아직 커밋 안 된 변경 데이터도 읽어 버린다.

쉽게 이해할 수 있는 문제를 발생시키니까 편하게 살펴보자

1.1. 발생 문제 예시 - Dirty Reads

product 테이블

product_idprice
......
740
  1. 트랜잭션 A가 product_id가 1인 상품 데이터의 price를 변경한다.
UPDATE product SET price = 100
WHERE product_id = 7

그러나 commit은 아직 하지 않았을 때. 다시 말해, 롤백될 수도 있을 때.

  1. 그때 트랜잭션 B가 같은 데이터를 읽는다.
SELECT * FROM product
WHERE productId = 7

커밋하지 않은 데이터도 읽으므로,
트랜잭션 B가 읽은 productprice100이다.

  1. 그런데 이 상태에서 트랜잭션 A가 롤백되면?
    트랜잭션 B는 잘못된 데이터를 읽은 것이 된다.

해결

해결 방법은 간단해.
커밋된 값만 읽게 하면 되거든.
; 커밋된 데이터와 트랜잭션 진행 중인 데이터를 따로 보관한다네.
; 격리 수준을 Read Committed로 높이는 거야.

1.2. 발생 문제 예시 - Dirty Writes

바로 위에서 커밋되지 않은 데이터를 읽을 때의 문제를 봤는데,
커밋되지 않은 데이터를 덮어쓸 때도 문제가 돼.

트랜잭션A는 김씨 -> 전씨로 200원을 송금하려 한다.
트랜잭션B는 김씨 -> 전씨로 800원을 송금하려 한다.
(송금 전 김씨의 잔액 1,000, 전씨의 잔액 1,000)

  1. 트랜잭션A가 김씨의 잔액을 뺀 후, 전씨의 잔액을 늘리기 전
UPDATE account
SET balance = 800
WHERE owner = '김씨'
  1. 그 사이에, 트랜잭션B가 김씨 -> 전씨로 800원을 송금했다.
UPDATE account
SET balance = 200
WHERE owner = '김씨'
UPDATE account
SET balance = 1800
WHERE owner = '전씨'
  1. 그 후, 트랜잭션A가 전씨의 잔액을 증가시킨다(덮어쓴다).
UPDATE account
SET balance = 1200
WHERE owner = '전씨'

결과

  • 트랜잭션 A만 처리했다면,
    김씨의 잔액 800, 전씨의 잔액 1200 => 합 2000

  • 트랜잭션 B만 처리했다면,
    김씨의 잔액 200, 전씨의 잔액 1800 => 합 2000

  • 트랜잭션 A와 B를 하나씩 처리했다면,
    김씨의 잔액 0, 전씨의 잔액 2000 => 합 2000

  • Read Uncommitted로 동시에 처리한 결과,
    김씨의 잔액 200, 전씨의 잔액 1200 => 합 1400

돈(600원)이 사라졌다!

--

아이템 소유권자 변경 예시

  1. 트랜잭션A (1)
UPDATE item set owner = '김씨'
WHERE item_id = 3
  1. 트랜잭션B
UPDATE item set owner = '전씨'
WHERE item_id = 3
UPDATE item set owner = '전씨'
WHERE item_id = 7
  1. 트랜잭션A (2)
UPDATE item set owner = '김씨'
WHERE item_id = 7

결과

  • 트랜잭션A의 기대
    item(id=3)의 소유자 김씨, item(id=7)의 소유자 김씨

  • 트랜잭션B의 기대
    item(id=3)의 소유자 전씨, item(id=7)의 소유자 전씨

  • 실제
    item(id=3)의 소유자 전씨, item(id=7)의 소유자 김씨

해결

마찬가지로 커밋된 데이터만 덮어쓰게 하면 돼.
; 행(row) 단위로 잠군다네.
; 그럼 같은 행을 변경 중인 트랜잭션이 있으면 기다린대.


여전한 문제

Read Committed 수준으로 커밋된 데이터만 읽고 덮어쓴다 해도 여전히 또 다른 문제가 발생할 수 있어.

아까는 변경 중인 걸 읽었을 때 문제가 발생했고 커밋된 것만 읽도록 해서 해결했지.
그런데, 읽는 도중에 읽었던 데이터가 다른 트랜잭션에 의해 변경(커밋까지)되는 상황은 어떨까?

(2편에서 계속..)

0개의 댓글