19.05.03 트랜잭션과 동시성 제어

Back-End/Data Base 2019. 5. 3. 22:39
728x90
반응형

-트랜잭션-

 

데이터베이스를 사용하는 실제 시스템이나 애플리케이션에서는 단일 쿼리만으로 조작하는 일은 거의 없고

복수의 쿼리를 연속적으로 사용해 일관성 있는 형태의 한 단위로 취급해야한다.

이러한 한 덩어리의 쿼리 처리 단위를 '트랜잭션'이라고 합니다.

 

MySQL에서는 트랜잭션을 사용할 수 없는 단순한 구조의 'MyISAM형'과 일반적인 DBMS와 똑같은

트랜잭션 구조를 사용할 수 있는 'InnoDB형' 2종류의 테이블을 이용할 수 있습니다.

이번 장에서는 트랜잭션을 사용하기 위해 InnoDB형 테이블을 작성합니다.

 

 

 

-트랜잭션의 4가지 특성(앞글자를 따서 'ACID 특성'이라고 한다.)-

 

 

  1. Atomicity (원자성) = 데이터의 변경 (INSERT/DELETE/UPDATE)을 수반하는 일련의 데이터 조작이

     전부 성공할지 실패할지 보증하는 구조 (전부 성공하거나 실패하거나)

 

  2. Consistency (일관성) = 일련의 데이터 조작 전후에 그 상태를 유지하는 것 (예를들어 속성에 유일성 제약을 걸면 중복된 번호 저장 불가)

 

  3. Isolation (고립성 또는 격리성) = 일련의 데이터 조작을 복수 사용자가 동시에 실행해도 '각각의 처리가 모순없이 실행되는 것을 보증한다' 는 것

 

  4. Durability (지속성) = 일련의 데이터 조작(트랜잭션 조작)을 완료(COMMIT)하고 완료 통지를 사용자가 받는 시점에서 그 조작이 영구적이

      되어 그 결과를 잃지 않는 것을 나타냅니다.

 

 

SQL 문은 몇가지 키워드와 테이블명, 열명 등을 조합해 하나의 문장을 만들어 쿼리의 내용을 기술하는데, 이중 키워드는

처음부터 의미나 사용법이 정해져 있는 특별한 영단어입니다. SQL문은 DBMS에 줄 수 있는 명령의 종류에 따라

다음 3가지로 구분됩니다.

 

데이터 정의 언어 (DDL) 

 데이터 조작 언어 (DML)

 데이터 제어 언어 (DCL)

 

 DDL은 데이터를 저장하는 그릇인 스키마

(데이터베이스) 또는 테이블 등을 작성하거나

제거합니다. DDL로 구분된 명령에서는

CREATE, DROP,ALTER 등이 있습니다.

 

 DML은 테이블의 행을 검색하거나 변경하는데 사용할 수 있습니다. DML로 구분된 명령에는

'SELECT (행의 검색), INSERT (행의 추가), UPDATE (행의 갱신), DELETE (행의 제거)

등이 있습니다.

 DCL은 데이터베이스에서 실행한 변경을

확정하거나 취소하는데 사용합니다.

COMMIT, ROLLBACK 등이 있습니다.

 

 

 

-MySQL의 특성-

 

 

  1. 읽기를 수행할 경우 갱신 중이라도 블록되지 않는다 (읽기와 읽기도 서로 블록되지 않는다)

 

  2. 읽기 내용은 격리 수준에 따라 내용이 바뀌는 경우가 있다.

 

  3. 갱신 시 배타적 잠금을 얻는다. 잠금은 기본적으로 행 단위로 얻으며 트랜잭션이 종료할 때까지 유지한다.

 

  4. 갱신과 갱신은 나중에 온 트랜잭션이 잠금을 획득하려고 할 때 블록된다. 일정 시간을 기다리며 그 사이에 잠금을 획득할 수 없는 경우에는

    잠금 타임아웃이 된다.

 

  5. 갱신하는 경우 갱신 전의 데이터를 UNDO 로그로 '롤백 세그먼트' 라는 영역에 유지한다. 이 'UNDO 로그'는 용도가 2가진데, 첫 번째는

     갱신하는 트랜잭션의 롤백 시 갱신 전으로 되돌리는 것이고, 두 번째는 복수의 트랜잭션으로부터 격리 수준에 따라 대응하는 갱신 데이터를

     참조하는데 이용한다.

 

 

 

 

-트랜잭션 격리 수준별 외관-

 

 

  반복 읽기 : 최초 쿼리를 실행한 시점에 커밋된 데이터를 읽어 들입니다.

                이 시점에서는 커밋된 읽기와 같습니다. 같은 쿼리를 여러번 실행하면 최초 읽은 내용의 결과 세트가 반환됩니다.

          복수 회의 쿼리 실행 사이에 다른 트랜잭션이 커밋했어도 그 내용은 반영되지 않습니다.

 

  커밋된 읽기 : 쿼리를 실행한 시점에서 커밋된 데이터를 읽어 들입니다.

   같은 쿼리를 여러번 실행하면 그 사이에 다른 트랜잭션에서 커밋할 때가 있는데, 이 경우 최신 쿼리의 실행 개시

   시점에서 커밋된 데이터를 읽습니다.

 

  갱신을 수행하는 트랜잭션 자신 : 트랜잭션 격리 수준이나 COMMIT/ROLLBACK에 상관없이 자신이 수행했던 갱신은 즉시 볼 수가 있습니다.

 

 

 

 

-잠금 타임아웃이란?-

 

'갱신' 과 '참조'는 서로를 블록하지 않지만, '갱신' 과 '갱신' 이 부딪치는 경우에는 나중에 온 갱신이 잠금 대기 상태가 됩니다.

잠금을 건 쪽이 언제 잠금을 풀지 알 수 없어서 잠금 해제를 기다리고 있는 쪽에서는 잠금을 기다리거나 기다리지 않거나,

기다린다면 어느 정도 기다릴지를 (초수 지정이나 무한으로 기다린다) 설정할 수 있습니다.

이때 잠금 대기로 타임아웃이 발생하는 경우 DBMS로부터 롤백되는 단위가 다를 때가 있는데, 해당 트랜잭션 전체를

롤백하는 경우와 쿼리만 롤백하는 것입니다.

MySQL 에서는 잠금 대기로 타임아웃이 발생하면 롤백되는 것은 기본으로 오류가 발생한 쿼리 입니다.

트랜잭션 전체를 롤백하고 싶다면 다음 방법으로 할 수 있습니다.

 

 

  타임아웃 오류 후 명시적으로 ROLLBACK을 실행한다.

 

  innodb_rollback_on_timeout 시스템 변수를 설정한다.

 

 

 

 

-교착 상태란?-

 

예를 들어, 트랜잭션 A가 테이블 a의 잠금을 얻고 트랜잭션 B가 테이블 b의 잠금을 얻었다고 해보겠습니다.

이 잠금을 유지한 채 서로 잠금을 건 자원에 잠금이 필요한 처리(INSERT/UPDATE/DELETE)를 실행하면 아무리

기다려도 상황이 바뀌지 않는 상태가 되는 것을 '교착 상태' 라고 합니다.

 

 

 

-교착상태의 빈도를 낮추는 대책-

 

DBMS 전반적인 대책 

 MySQL의 대책

 

 1. 트랜잭션을 자주 커밋한다.

    트랜잭션이 작은 단위가 되어 교착상태의 가능성을 낮춘다.

 

 2. 정해진 순서로 테이블(행)에 액세스 하게 한다.

 

 3. 필요 없는 경우에는 읽기 잠금 획득(SELECT ~ FOR UPDATE 등)의

    사용을 피한다.

 

 4. 쿼리에 의한 잠금 범위를 더 좁히거나 잠금 정도를

     더 작은 것으로 한다.

 

 5. 한 테이블의 복수 행을 복수의 연결에서 순서 변경 없이

    갱신하면 교착 상태가 발생하기 쉽다.

    동시에 많은 연결에서 갱신 때문에 교착 상태가 자주 발생한다면

    테이블 단위의 잠금을 획득해 갱신을 직렬화하면 동시성은 떨어지지만

    교착상태는 회피할 수 있어서 전체 처리로 보면 좋은 예도 있다.

 

 6. 테이블에 적절한 인덱스를 추가해 쿼리가 이를 이용하게 한다.

    인덱스가 사용되지 않는 경우에는 필요한 행의 잠금이 아닌

    스캔한 행 전체에 대해 잠금이 걸리게 한다.

 

 

 

 

  단원 정리

 

  1. DBMS의 트랜잭션은 'ACID'의 특성이 있다.

 

  2. 트랜잭션은 원자성에 의해 전부 성공하거나 전부 실패하는 원칙으로 동작한다.

 

  3. 고립성에 따라 병렬 실행이 일관성 있게 수행된다.

 

  4. 트랜잭션에는 4가지 격리 수준이 있는데, 직렬화 기능 이외의 수준을 선택하면 3가지의 현상이 발생한다.

   실제 운용에서는 '커밋된 읽기' 또는 '반복 읽기'의 격리 수준을 이용한다.

 

  5. 트랜잭션에서 잠금 대기와 교착 상태는 피할 수 없으므로 적절히 대처하는 것이 필요하다.

 

  6. 오토커밋은 쿼리 단위로 커밋하는 설정인데, 주의해서 사용하지 않으면 트랜잭션의 혜택을 받지 못할뿐더러 성능에 악영향을 미친다.

 

 

728x90
반응형
: