[DB] 데이터베이스 트랜잭션

EHOI·2023년 2월 3일
0

DB

목록 보기
2/6

트랜잭션

용어

  • 트랜잭션
    • 한 작업의 단위이다.
    • 내가 친구한테 30,000원을 송금하려고 할 때, 송금이라는 작업을 위해서 1) 해당 계좌에 잔액이 30,000원 이상 있는지 확인하고 2) 있다면 내 계좌에서 30,000원을 감하고 3) 친구의 계좌에 30,000원을 증가시켜야 한다. 이것을 하나의 트랜잭션이라고 할 수 있다.
  • 커밋
    • 여러 쿼리를 수행하고, 이것을 영구적으로 데이터베이스에 적용하겠다는 의미다.
    • Git을 사용할 때도 내가 작업한 단위별로 커밋을 해서 반영하듯 비슷한 개념이다.
  • 롤백
    • 이전 상태로 되돌리는 것이다.
    • 어떤 작업(트랜잭션)을 처리했는데, 처리하기 전으로 돌리는 일이다.

트랜잭션 특징 ACID

  • Atomicity 원자성
    • All or Nothing 으로 이해하면 쉽다.
    • 모두 처리되어야 하거나 실패하면 모두 처리되지 않아야 하는 개념이다.
    • 위에서 예를 든 송금 트랜잭션에서, 내 계좌에서는 30,000원이 빠져나가고 친구 계좌에는 30,000원이 들어오지 않은 그런 일은 없어야 한다는 것이다.
  • Consistency 일관성
    • 일관성이 없다는 것은, 어떨 때는 이랬다가 또 다른 때는 저랬다가 한다는 것이다.
    • 항상 같은 방식으로 작업을 수행해야 한다는 것이다.
    • ‘계좌에 잔액이 없다면 송금이 불가능하다’고 원칙을 정했다면 항상 그래야 한다.
  • Isolation 격리성
    • 모든 트랜잭션은 독립적이어서 하나의 트랜잭션이 일어날때 다른 트랜잭션이 끼어들면 안된다.
    • 이와 관련해서는 격리성의 수준이 정해져 있는데, 밑에서 다시 다룬다.
  • Durablity 지속성
    • 완료된 트랜잭션은 데이터베이스에 영원히 반영되어야 한다.

트랜잭션의 격리성

격리성에는 여러 단계가 있다.

그 이유는 격리성을 철저히 지켜서 트랜잭션이 모두 독립적으로 하나씩 수행되도록 한다면 그만큼 시간이 오래 걸려서 성능이 떨어진다. 이것을 동시성이 낮아진다고 한다.

즉, 격리성과 동시성은 반비례하다.

격리성의 수준을 알아보자. (가장 높은 것부터 나열)

  1. SERIALIZABLE
    • 말 그대로 직렬화되어 있으니, 트랜잭션을 하나씩 수행한다.
    • 그러므로 여러 트랜잭션이 한꺼번에 같은 행을 처리하기 위해 달려들 수 없다.
  2. REPEATABLE_READ : 반복가능한 것을 읽을 수 있다. (그럼 이 단계보다 낮아지면 반복 가능하지 않은 것도 읽을 수 있나?)
    • 커밋 완료된 데이터만 조회할 수 있다. 지금 다른 트랜잭션이 그 행을 건들고 있다면 읽을 수 없는 것이다. 이미 커밋이 완료가 됐으니 그 행은 몇 번을 읽더라도 같은 값이라는 것을 보장한다는 뜻이다. (전체 테이블이 같은 값이라는 것은 보장 못함)
    • 이 단계에서는 하나의 트랜잭션이 작업을 할 때, 완료된 것에 대해서 읽기만 될 뿐 수정은 안된다.
    • 근! 데! 새로운 행을 만드는 작업, 즉 기존 작업을 건드리지 않는 작업은 허용한다.
    • 그래서 기존의 행을 조회할 때는 아무런 변화가 없지만, 추가된 행이 발견될 수도 있다. (전체 테이블이 바뀔 수도 있다는 것을 말함)
    • 그래서 유령이 왔다간 것처럼 팬텀 리드가 나타날 수 있다.
    • MySQL에서 기본값으로 설정되어 있다.
  3. READ_COMMITTED : 커밋된 것을 읽는다. (그럼 이 단계보다 낮아지면 커밋되지 않은 것도 읽나?)
    • 커밋 완료된 데이터만 조회할 수 있다. 하지만 REPEATABLE_READ처럼 보장해주지 않기 때문에
    • 팬텀 리드 + 반복가능하지 않은 조회가 일어날 수 있다.
    • PostgreSQL, SQL Server, 오라클에서 기본값으로 설정되어 있다.
  4. READ_UNCOMMITTED : 커밋되지 않은 것도 읽을 수 있다.
    • 가장 낮은 격리 수준이다.
    • 그렇기에 동시성이 높아 가장 빠르다.
    • 그래서 성격이 급해서 다른 트랜잭션이 아직 커밋도 하지 않았는데, 그 값을 읽어 올 수 있다.
    • 팬텀 리드 + 반복가능하지 않은 조회 + 더티 리드가 일어날 수 있다.

격리성에 따르는 문제점

위 격리성 수준에서 (괄호 안의 내 생각처럼) 문제점을 유추해볼 수 있다.

  1. SERIALIZABLE
    • 하나씩 모두 격리되어 트랜잭션을 수행하므로 아무런 문제가 일어나지 않는다.
  2. REPEATABLE_READ
    • 여기서는 **팬텀 리드**라는 현상이 나타난다.
    • 내가 같은 쿼리를 두번 보냈는데, 첫번째 쿼리 결과와 두번째 쿼리 결과가 다른 것이다.
    • 마치 유령이 나타난 것 같다고 해서 팬텀 리드다. (귀엽)
    • 다른 트랜잭션에서 행이 추가가 됐든 삭제가 됐든 하면서 내 트랜잭션 결과과 달라지는 것이다.
  3. READ_COMMITTED
    • 반복 가능한 조회는 2번 격리 수준까지 보장한다.
    • 그렇다면 여기서는 반복 가능하지 않은 조회가 나타날 수 있다, 는 것을 이름에서 유추해볼 수 있다.
    • 그리고 이 수준에서는 ‘커밋된 것은 읽는다’는 것을 보장할 수 있다.
    • 반복 가능하지 않은 조회란, 같은 행을 조회를 했는데 그 값이 다른 것을 말한다.
    • 위의 팬텀 리드와는 다르게 이 현상은 같은 행만을 이야기 한다. 팬텀 리드는 테이블 전체를 얘기하는 것 같다. ****
  4. READ_UNCOMMITTED
    • 여기서는 3 수준에서는 보장해주지 않는, 커밋되지 않은 것까지 읽는 더티 리드가 발생할 수 있다.
    • 다른 트랜잭션에서 커밋을 했다가 롤백을 했는데, 내 트랜잭션에서는 커밋이 됐다고 판단하고 읽어들이는 것이다.
    • 타이밍이 안 맞은 거다. —- 다른 트랜잭션 커밋(잔액 : 100) —- 내 트랜잭션에서 조회(잔액 : 100) —- 다른 트랜잭션 롤백(잔액 : 200) ⇒ 200이 조회되었어야 했는데, 트랜잭션이 동시에 이루어지다 보니 이런 문제가 발생한 것이다.

이 격리 단계는 모두 조정할 수 있고, 일례로 MySQL에서는 다음과 같이 작성할 수 있다.

set session transaction isolation level serializble;
profile
#성장 #단단함 #평온함

0개의 댓글