7장 트랜잭션과 동시성 제어

양시준·2022년 3월 31일
0
post-thumbnail

6장은 기본 SQL문법을 다루는데 굳이 정리할 필요를 느끼지 않아서 작성하지 않았다.

트랜잭션이란?

데이터베이스의 상태를 변화시키기 해서 수행하는 작업의 단위를 뜻한다.

하나 이상의 쿼리가 트랜잭션의 단위가 된다.

예를 들면,
A가 B에게 송금 할 때

  1. A의 잔고에서 돈을 빼냄
  2. B의 잔고에 A가 송금한 만큼 돈을 추가함

위 두가지 처리가 하나의 트랜잭션이 된다.

트랜잭션의 4가지 특성

원자성 - Atomicity

트랜잭션의 결과는 전부 성공하거나 전부 실패해야한다.

트랜잭션 진행 중 실패가 일어난다면 ROLLBACK을 실행해 트랜잭션 실행 이전으로 돌아간다.

예시

"트랜잭션이란?"에서 설명한 예시에서 1번이 완료된 이후 2번에서 실패가 일어났지만 1번이 그대로라면 A는 돈을 잃고, B는 돈을 받지 못하는 문제가 발생한다.

일관성 - Consistency

일련의 데이터 조작 전후에 그 상태를 유지해야한다.

데이터베이스 오브젝트에 정합성 제약을 추가하여 유지한다.

예시

각각의 유저가 고유한 ID를 가져야 한다면 ID 컬럼에 UNIQUE 조건을 추가하여 ID 컬럼의 값이 중복되지 않도록 할 수 있다.

고립성 / 격리성 - Isolation

일련의 데이터 조작을 여러 사용자가 동시에 실행되도 각각의 처리가 모순 없이 실행되는 것을 보장한다.

여기에서 설명한 '모순 없다'는 것은 무슨 뜻일까?

복수의 트랜잭션이 순서대로 실행되는 경우와 같은 결과를 얻을 수 있는 상태를 말한다.

이것을 트랜잭션 격리 수준(Transaction Isolation Level)이라고 하는데, 자세한 내용은 다른 글을 참고하길 바란다.

트랜잭션 격리 수준 - Transaction Isolation Level

예시

A와 B, 두 사용자가 있다. 하나의 컬럼의 값을 변경하려고 한다.

  1. 계좌을 조회한다.
  2. 계좌에 1을 뺀 값을 넣는다.

1이 진행되는 중에 두 사용자가 같은 계좌을 조회한다면 같은 값을 조회하게 된다.

이를 10이라고 가정했을 때, 2를 진행하게 되면 A는 10 - 1인 9로 값을 변경한다.

마찬가지로, B 역시 9로 값을 변경한다.

두 사용자 모두 같은 계좌에서 1 씩 감소시켰고, 결과는 8 이 되야하지만 9이다.

이러한 일을 막기 위해서 테이블이 수정 될 때 다른 사용자가 접근하지 못하도록 LOCK을 걸어서 후속 처리를 BLOCK한다.

지속성 - Durability

일련의 데이터 조작을 완료하고 완료 통지를 받는 시점에 그 조작은 영구적으로 되어 그 결과를 잃지 않는 것을 말한다.

이는 시스템이 정상일때 뿐만 아니라 데이터베이스나 OS의 이상 종료, 즉 시스템 장애도 견딜 수 있다는 뜻이다.

지속성을 보장하기 위해 많은 DBMS에서는 트랙잭션 조작을 하드디스크에 로그 라는 형태로 기록하고 있다.

시스템에 이상이 발생하면 로그를 이용해 이상 발생 전의 상태까지 복원한다.

다른 커넥션에선 어떻게 보일까

기본적으로 DDL 이나 DML에 의한 데이터 저장은 트랜잭션이 커밋되기 전까지는 다른 커낵션에서 보이지 않는다.

하지만 이에 상관없이 다른 커녁션에서 보이는 경우가 있다.

오토커밋 설정

트랜잭션의 개시가 명시적으로 지정되지 않았을 때 구별하는 방법으로 2가지 모드가 있다.

  1. 하나의 SQL 문이 하나의 트랜잭션으로 구분된다.
  2. 사용자가 COMMIT 또는 ROLLBACK을 실행하기 전까지가 하나의 트랜잭션이 된다.

여기서 1 번 (오토커밋)인 경우 자신이 COMMIT을 명시하지 않아도 자동적으로 COMMIT이 되기 때문에 다른 커넥션에서 보이게 된다.

DDL에 따은 암묵적인 커밋

DBMS 마다 차이가 있지만 Oracle이나 MySQL에서는 DDL 문 실행시 암묵적인 커밋이 발생한다.

잠금 타임아웃과 교착 상태

잠금 타임아웃이란

'갱신'과 '참조'는 서로를 블록하지 않지만, '갱신'과 '갱신'이 부딪치는 경우 늦게 온 갱신이 대기 상태가 된다.

이 때 잠금을 건 쪽이 언제 잠금을 풀지 알 수 없으니 기다리지 않거나, 기다린다면 얼마나 기다릴지 설정할 수 있다.

기다리는 시간이 설정했던 시간보다 길어진다면 잠금 타임아웃이 발생하는 것이다.

교착 상태란

예시

트랜잭션 A와 B 가 있고, 테이블 a, b가 있다.

트랜잭션 A는 테이블 a의 잠금을 얻고 b를 갱신하고자 한다.
트랜잭션 B는 테이블 b의 잠금을 얻고 a를 갱신하고자 한다.

이 경우 아무리 기다려도 상황이 바뀌지 않는 상태가 되는데 이를 교착 상태라고 한다.

교착 상태의 대책

  • 트랜잭션을 자주 커밋한다.
    • 더 작은 단위가 되어 교착상태의 가능성을 낮춘다.
  • 정해준 순서로 테이블에 액세스하게 한다.
  • 필요없는 경우 읽기 잠금의 사용을 피한다.
  • 쿼리에 의한 잠금 범위를 더 좁히거나 잠금 정도를 더 작은 것으로 한다.
  • 한 테이블에서 복수 행을 복수 연결하여 교착 상태가 자주 일어난다면 테이블 단위의 잠금을 사용한다.
    • 이 경우 동시성을 떨어지지만 교착상태는 처리할 수 있어 결과적으로 좋은 결과가 나오기도 한다.

해서는 안되는 트랜잭션 종류

별 이유가 없다면 아래 방식의 트랜잭션은 사용하지 않는 것이 좋다.

오토커밋

여러 DBMS에서 기본적으로 오토커밋을 사용하는데 간단한 쿼리의 실행과 테스트를 하는 경우에는 편리하지만 그 이외의 경우에는 부하가 커 추천하지 않는다.

긴 트랜잭션

  • 대량 처리를 한개의 트랜잭션으로 실행한다.
  • 아무것도 하지 않는 트랜잭션을 유의한다.
  • 트랜잭션 중에 대화(사용자가 반응해야 진행되는) 처리를 넣는다.
  • 처리 능력 이상의 트랜잭션 수

0개의 댓글