[Database] Transaction 1

Seongje kim, 07 October 2020

데이터베이스 트랜잭션에 대한 내용입니다.

트랜잭션(Transaction)


트랜잭션은 데이터베이스의 상태를 변화시키는 하나의 논리적 기능을 수행하기 위한 작업의 단위 또는 한꺼번에 모두 수행되어야 할 일련을 연산들을 의미한다.

트랜잭션의 특징

  1. 트랜잭션은 데이터베이스 응용 프로그램 또는 시스템에서 사용자의 요구 사항에 응답하기 위한 상태 변환, 병행 제어, 회복 작업 등의 시스템 내부적으로 처리되는 작업의 논리적 단위로써 하나의 데이터베이스 응용 프로그램은 트랙잭션들의 집합으로 표현된다.
  2. 하나의 트랜잭션은 Commit 되거나 Rollback 된다.

Commit 연산

하나의 트랜잭션에 대한 작업이 성공적으로 완료되어 데이터베이스가 다시 일관성있는 상태가 되었을 때, 해당 작업이 완료되었다는 것을 알려주기 위해 사용되는 연산이다.

Rollback 연산

하나의 트랙잭션 처리가 비정상적으로 종료되어 해당 트랜잭션의 원자성이 깨진 경우, 이 트랜잭션의 일부 연산이 정상적으로 처리되었더라도 트랜잭션의 원자성을 구현하기 위해 트랜잭션을 처음부터 다시 시작하거나 이미 연산된 결과들을 모두 취소한다. 즉, Rollback 시에는 해당 트랜잭션을 재시작하거나 폐기한다.

트랜잭션의 필요성

데이터베이스 서버에 여러 개의 클라이언트가 동시에 액세스 하거나 응용 프로그램 내부에서 연산을 처리 과정에서 중단될 수 있는 경우 등 의도하지 않은 결과가 발생하지 않도록 사전에 방지한다. 다시 말해, 어떤 서비스 요청을 병렬로 처리할 수 밖에 없는 현실적인 상황으로 인한 데이터 부정합 문제를 트랙잭션을 사용하여 방지할 수 있다.

트랜잭션의 성질(ACID)


원자성(Atomicity)

트랜잭션의 모든 연산들이 정상적으로 수행 완료되거나 반대로 어떠한 연산도 수행되지 않는 상태를 보장해야한다. 즉, 트랜잭션의 작업이 부분적으로 실행되거나 중단되지 않음을 의미한다. (All or Nothing)

트랜잭션에서의 원자성은 수행하고 있는 트랜잭션에 의해 변경된 내역을 유지하면서, 이전에 Commit 된 상태를 임시 영역인 롤백 세그먼트(Rollback Segment)에 따로 저장함으로써 보장한다. 현재 수행하고 있는 트랜잭션에서 어떤 오류가 발생하면 현재 변경 내역을 지우고, 롤백 세그먼트에 저장했던 상태로 Rollback 하는 것이다.

하지만 원자성을 구현하기 위해 확실하게 오류가 발생하지 않은 부분도 다시 처음부터 작업을 수행해야 하는 손해가 발생한다. 따라서 확실한 부분에 대해서는 Rollback 되지 않도록 중간 Save Point를 지정할 수 있다.

일관성(Consistency)

트랜잭션 완료 후에도 데이터베이스는 일관된 상태로 유지되어야 한다. 즉, 트랜잭션의 작업 처리 결과가 항상 일관성이 있어야 함을 뜻하며, 시스템이 가진 여러 고정된 요소들의 상태가 작업 처리 전/후의 상태가 같아야 한다.

트랜잭션 수행 전/후에 데이터 모델의 모든 제약 조건(기본키, 외래키, 도메인, 도메인 제약조건 등)을 만족하는 것을 통해 일관성을 보장한다. 어떤 이벤트와 조건이 발생했을 때, 데이터베이스 시스템이 자동적으로 수행할 동작을 명시한 트리거(Trigger)를 통해 일관성 검사를 수행한다.

독립성(Isolation)

둘 이상의 트랜잭션이 동시에 병렬 실행되는 경우, 하나의 트랜잭션이 실행되는 동안 다른 트랜잭션의 작업이 간섭하지 못하도록 보장함을 말한다. 하나의 트랜잭션이 완료되기 전까지 변경된 데이터는 다른 트랜잭션에서 참조하지 못한다.

영속성(Durability)

성공적으로 완료된 트랜잭션의 연산 결과는 시스템이 고장나더라도 영구적으로 반영되어야 한다.

동시성 제어(Locking)


다중 사용자 환경에서 둘 이상의 트랜잭션이 동시에 수행될 때, 병렬 처리와 함께 트랜잭션의 일관성과 독립성을 보장하기 위한 트랜잭션의 데이터 접근 제어를 말한다.

동시성 제어는 ‘Locking’ 기법으로 수행된다. OS의 세마포어와 비슷한 개념으로 여러 개의 트랜잭션들이 하나의 데이터로 동시에 접근하려고 할 때, 이를 제어해주는 도구로써 Lock이 사용된다. Lockshared_lockexclusive_lock으로 나뉘며 상황에 맞추어 lockunlock를 수행한다.

  • shared_lock : 읽기 전용, 데이터 쓰기를 허용하지 않고 오직 읽기만 허용
  • exclusive_lock : 데이터를 쓸 때 다른 트랜잭션의 읽기 및 쓰기 금지, 작업 완료 후 unlock

하지만 단순히 Locking 기법을 사용한다면 경우에 따라 일관성이 위배되거나 데드락(Deadlock) 상태에 빠질 수 있다. 따라서 이를 방지하기 위한 프로토콜이 존재한다.

2PL 프로토콜(2 Phase Locking Protocal)

2PL 프로토콜이란 여러 트랜잭션이 공유하고 있는 데이터에 동시에 접근할 수 없도록 하기 위한 프로토콜로써 트랜잭션들이 lock을 하는 시간과 unlock을 하는 시간을 구분하여 수행하도록 한다. 즉, Lock을 걸고 해제하는 시점에 제한을 두지 않으면 경우에 따라 데이터의 일관성이 깨지거나 데드락 상태에 빠질 수 있기 때문에 Locking 단계를 2개로 구분하여 이를 방지하는 방법이다.

  • 확장 단계(Growing Phase) : 트랜잭션은 새로운 lock만 할 수 있고, unlock은 할 수 없는 단계
  • 축소 단계(Shrinking Phase) : 트랜잭션은 unlock만 실행할 수 있고, lock은 실행할 수 없는 단계

2PL 프로토콜의 목적은 이 확장 단계와 축소 단계가 섞이지 않게 하는 것이다. 즉, lockunlock이 번갈아 수행되지 않고, lock이 모두 수행된 후 unlock이 수행되어야 한다.

결과적으로 트랜잭션 병렬 처리를 위한 직렬 가능성을 보장하면서 동시에 일관성과 독립성을 보장할 수 있게 된다.