본문 바로가기
행위 돌아보기

DB 트랜잭션 조금 이해하기 - 최범균 유튜브 리뷰

by simplify-len 2021. 8. 1.

최범균님 강의로 DB 트랜잭션 조-쪼금 이해하기 1,2

https://youtu.be/poyjLx-LOEU

개발자 관점에서 트랜잭션은 간단하게 여러 읽기/쓰기 를 논리적으로 하나로 묶음

  • 트랜잭션 시작 - 여러 쿼리 실행 - 커밋 또는 롤백
  • 모두 반영(커밋) 또는 모두 반영하지 않거나(롤백)

이런 트랜잭션이 없다면?

image-20210801210013412

1.3 에서 실패할 경우, 1.2 업데이트을 취소할 수 있는 것을 구현해야 한다.

트랜잭션 범위는 커넥션 기준으로 합니다.

image-20210801210106622

만약 5 에서 롤백될 경우, 4,3 의 롤백 되고, 그 뿐만 아니라 4.1 에서 롤백도 기대하게 됩니다.

그러나, 4.1 처럼 새로운 트랜잭션을 만들었다면 4.3 에서 이미 commit 되었기 때문에 롤백되지 않습니다.

여러 메소드를 호출할 때 하나의 트랜잭션으로 묶고 싶다면, 여러 메소드에서 하나의 커넥션을 사용할 수 있는 그런 방법을 뜻합니다. 트랜잭션 전파가 바로 이런 목적에 사용됩니다.

여러 메서드 호출이 한 트랜잭션에 묶이도록 하기 위해 필요합니다.

  • 예 - 스프링 프레임워크의 트랜잭션 처리
    • 메서드 간에 커넥션 객체를 전달하지 않아도 한 트랜잭션으로 묶어서 실행

image-20210801210435457

트랜잭션에 외부연동이 있을 경우 주의해야 합니다!

image-20210801210552939

첫번째 그림에서 4번에서 문제가 발생할 경우, 2,3 은 롤백에 문제가 없을 것입니다. 그러나, 두번째 그림에서는 외부 API 가 이미 성공했다면 이는 롤백될 수 없습니다.

글로벌 트랜잭션이라는 것도 있습니다.

image-20210801210750261

정리하면

  • 원자성에 대한 내용이였습니다
    • All or Nothing
  • 트랜잭션 범위 중요
    • 문제가 발생했을 때 롤백해야 하는 범위

2번째

격리

같은 데이터에 동시 접근

  • 동시성은 초심자가 놓치기 쉬운 문제가 발생
  • 예: 당직 담당자를 최소 1명 유지해야 한다면?

image-20210801211149848

경쟁 상태(Race Condition)

  • 여러 클라이언트가 같은 데이터에 접근할 때 문제가 발생한다.

  • 트랜잭션 격리(Isolation)

    • 트랜잭션을 서로 격리해서 다른 트랜잭션이 영향을 주지 못하게 함
  • 가장 쉬운 방법은 트랜잭션을 순서대로 실행

    • 동시접근 문제 아예 없음
    • 하지만 한 번에 한 개 트랜잭션만 처리하므로 성능(처리량)저하 가능
  • 다양한 격리 수준 지원

    • Read Uncommitted
    • Read Committed
    • Repeatable Read
    • Serializable

동시성 관련 다양한 문제들을 살펴보면서 격리 수준을 이해할 수 있습니다

  • 커밋되지 않은 데이터 읽기
  • 커밋되지 않은 데이터 덮어쓰기
  • 읽는 동안 데이터 변경 1
  • 변경 유실
  • 읽는 동안 데이터 변경 2

커밋되지 않은 데이터 읽기 (dirty read)

image-20210801211657859

커밋되지 않은 데이터 덮어쓰기

image-20210801212016450

위 두 문제를 해결하기 위해서 Read Committed 를 제공합니다.

오직 커밋된 데이터만 읽는 행위를 말합니다.

  • 커밋된 데이터만 읽기
    • 커밋된 값과 트랜잭션 진행 중인 값을 따로 보관
  • 커밋된 데이터만 덮어쓰기
    • 행 단위 잠금 사용
      • 같은 데이터를 수정한 트랜잭션이 끝날 때까지 대기

읽는 동안 데이터 변경1 - Read skew

읽는 시점에 따라 데이터가 바뀜

image-20210801212608304

처음에 A,B는 10입니다. 검은 사용자가 A를 조회할 때 10이라는 결과물을 가지고, 하얀사용자가 그 사이에 데이터를 변경하게 되면 검은 사용자가 커밋 이후에 데이터를 조회할 경우 B가 9 나오는 문제가 발생합니다.

이러한 READ SKEW 를 해결하기 위해서 Repeatable Read 가 나왔는데, 이는 트랜잭션 동안 같은 데이터를 읽게 하는 행위를 말합니다.

다시 말해, 데이터가 변경되더라도 같은 데이터를 읽을 수 있도록 하는 것을 말합니다.

image-20210801213338838

읽는 시점에 해당 버전에 해당하는 값만 읽습니다.

Read Committed 와 Repeatable Read 를 하더라도, 문제가 발생할 수 있습니다.

변경한 내용이 유실할 수 있습니다. 이를 Lost Update 라고 합니다.

같은 데이터를 쓸 때 발생하는데, 예를 들어 Count를 증가하거나 위키 페이지를 수정할 경우 발생합니다.

image-20210801214123644

변경 유실에 대해서 3가지 처리 방식이 있습니다.

  1. 원자적 연산 사용

  2. 명시적인 잠금

  3. CAS(Compare And Set)

DB가 지원하는 원자적 연산 사용

  • 동시 수정 요청에 대해 DB가 순차 처리

  • 예) update article set readcnt = readcnt + 1 where id = 1

명시적 잠금

  • 조회할 때 수정할 행을 미리 잠금
    • 예: select ... for update

image-20210801214721756

CAS(Compare And Set)

  • 수정할 때 값이 같은지 비교

image-20210801214839884

읽는 동안 데이터 변경 2

  • 한 트랜잭션의 결과가 다른 트랜잭션의 퀴리 결과에 영향
    • 같은 데이터를 쓰지 않지만 실제로는 경쟁 상태
    • 두 트랜잭션이 서로다른 데이터를 업데이트 하니까 경쟁상태가 아닙니다. 이런 문제를 해결하기 위해서 Serializable 을 사용합니다.

Serializable

  • 인덱스 잠금이나 조건 기반 잠금 등을 사용합니다.

image-20210801215315453

정리하면

  • 동시성은 초보자가 놓치기 쉬운 문제입니다.

    • 동시성 문제와 격리 수준을 이해하면 문제 발생을 줄일 수 있습니다.
  • 잠금 시간은 최소화해야 합니다.

    • 잠금 시간이 길어지면 성능(처리량) 저하
  • 동시성 문제를 다룰 때는 다음을 알면 좋습니다.

    • 사용하는 DB의 기본 격리 레벨
    • DB의 격리 레벨 동작 방식
  • mysql 은 Repeable-read

  • postgres 은 Read Committed

  • oracle 은 Read Committed

  • mongodb 는 Read uncommitted

댓글