[Data Base] Transaction & ACID

Jae ·2021년 11월 11일
0

Data Base

목록 보기
2/7

ACID라고 하는 성질은 데이터베이스에서 어떤 하나의 데이터를 처리하는 데 필요한 트랜잭션을 위한 성질이다. 여기서 트랜잭션은 뭘까? 계좌이체의 결제 과정을 생각해보자.

  • 구매자의 계좌에서 돈이 10,000원 출금된다.
  • 판매자의 계좌에 돈이 10,000원 입금된다.

위 과정을 진행한다고 했을 때 쿼리문을 아래처럼 쓸 수 있다.

거래가 일어날 때 실행되는 쿼리문

UPDATE accounts
SET balance = balance - 10000
WHERE user ='구매자';
UPDATE accounts
SET balance = balance + 10000
WHERE user ='판매자';

근데 만약에 계좌 이체 도중에 아래처럼 어떤 오류나 문제가 발생한다면...?

  • 구매자의 계좌에서 돈이 출금된 뒤, DB가 다운된다.
  • 구매자의 계좌에서 돈이 출금되지 않았는데, 판매자에게 돈이 입금된다.
  • 출금도 입금도 되지 않는다.

이런 상황에서는 어떻게 할 수 있을까?

전부 없었던 일로 해줘야 한다. 즉 데이터를 초기 상태로 되돌려줘야 한다. 이 초기 상태로 되돌려주는 일을 트랜잭션이 수행하는 것이다.

트랜잭션


  • 트랜잭션은 사용자 혹은 시스템 상의 실수가 있더라도 데이터베이스가 데이터를 안정적으로 보장할 수 있도록 한다.
  • 트랜잭션이란 여러 개의 작업을 하나로 묶어서 쿼리들이 한꺼번에 모두 실행되거나 아예 아무 쿼리도 실행되지 않게 해주는 실행 유닛이다.
  • 하나의 트랜잭션이 모두 실행되거나 아무 쿼리도 실행되지 않는다는 것을 커밋 혹은 롤백된다 라고 한다.
    • 커밋 : 일종의 확인 도장으로 트랜잭션으로 묶인 모든 쿼리가 성공되어 트랜잭션 쿼리 결과를 실제 DB에 반영하는 것
    • 롤백 : 쿼리 실행결과를 취소하고 DB를 트랜잭션 이전 상태로 되돌리는 것
  • 각 트랜잭션은 하나의 특정 작업으로 시작을 해 묶여 있는 모든 작업을 다 완료해야 정상적으로 종료한다.
  • 만약 하나의 트랜잭션에 속해있는 여러 작업 중에서 단 하나의 작업이라도 실패하면, 이 트랜잭션에 속한 모든 작업을 실패한 것으로 판단한다.

다시 말해 작업이 하나라도 실패를 하게 되면 트랜잭션도 실패이고, 모든 작업이 성공적이면 트랜잭션 또한 성공이다. 성공 또는 실패 라는 두 개의 결과만 존재하는 트랜잭션은, 미완료된 작업 없이 모든 작업을 성공해야 한다.

이 트랜잭션은 ACID라는 특성을 가지고 있는데, 트랜잭션이 안전하게 수행된다는 것을 보장하기 위한 성질이다.

트랜잭션의 성질

① Atomicity (원자성)

트랜잭션은 DB에 모두 반영되거나, 전혀 반영되지 않아야 한다. 즉 완료되지 않은 트랜잭션의 중간 상태를 DB에 반영해서는 안 된다.
원자성이 보장되면 구매자의 돈이 계좌에서 빠져나갔는데 판매자의 계좌에 돈이 들어오지 않는 일이 없을 것이다.

② Consistency (일관성)

트랜잭션 작업 처리 결과는 항상 일관성 있어야 한다. 데이터베이스는 항상 일관된 상태로 유지되어야 한다.

③ Isolation (독립성)

둘 이상의 트랜잭션이 동시 실행되고 있을 때, 어떤 트랜잭션도 다른 트랜잭션 연산에 끼어들 수 없다. 각각의 트랜잭션은 서로 간섭 없이 독립적으로 이루어져야 한다는 것이다.

④ Durability (지속성)

트랜잭션이 성공적으로 완료되었으면 결과는 영구히 반영되어야 한다.

ACID 성질은 트랜잭션이 이론적으로 보장해야 하는 성질이고 실제로는 성능을 위해 성질 보장이 완화되기도 한다. 예를 들어 독립성을 완벽하게 보장하려고 하면 동일 데이터에 100개의 연결이 접근했을 시, 이 100개 연결을 순차적으로 실행해야 한다. 이때 동시성이 매우 떨어지는 문제가 발생하게 되는데, 동시성을 얻기 위한 한 가지 방법으로 트랜잭션의 격리 레벨 설정을 할 수 있다.

트랜잭션 격리 수준

동시에 DB에 접근할 때 그 접근을 어떻게 제어할지에 대한 설정으로, 표준적으로 네 가지의 레벨이 존재한다.

① READ-UNCOMMITTED
② READ-COMMITTED
③ REPEATABLE-READ
④ SERIALIZABLE

밑으로 갈수록 격리 수준이 높아지지만 성능이 떨어진다. 데이터가 정합성과 성능이 반비례하므로 케이스에 맞게 적절히 선택하는 것이 중요하다.

① READ-UNCOMMITTED

  • 격리 수준이 가장 낮다
  • 한 트랜잭션이 아직 커밋 되지 않은 상태임에도 불구하고 변경된 값을 다른 트랜잭션에서 읽을 수 있다.

② READ-COMMITTED

  • 커밋이 완료된 데이터만 다른 트랜잭션에서 조회 가능

  • 트랜잭션이 이루어지는 동안 다른 사용자는 해당 데이터에 접근 불가

  • 아직 커밋하지 않은 상태라면 트랜잭션 시작 전 데이터를 불러옴

  • 커밋하면 변경된 데이터를 불러옴

    READ-COMMITTED 레벨에서는 Non-Repeatable Read, Phantom Read 현상이 발생한다. 이 현상은 같은 트랜잭션 내에서 SELECT 문을 두 번 조회했는데, 두 값이 다른 값이 출력되는 데이터 불일치 문제를 말한다.

③ REPEATABLE-READ

  • 트랜잭션 범위 내에서 조회한 내용이 항상 동일함을 보장
  • READ-COMMITTED처럼 커밋이 완료된 데이터만 읽을 수 있다.
  • 하지만 다른 점으로 한 트랜잭션이 종료될 때까지 다른 트랜잭션이 변경하거나 삭제하는 것을 막음으로써 한 번 조회한 데이터는 반복적으로 조회해도 같은 값을 반환한다. 그러나 이 레벨에서도 Phantom Read라는 문제가 발생한다. Phantom Read는 Non-Repeatable Read의 한 종류인데 조건이 걸렸든 안 걸렸든 SELECT 문을 쓸 때 나타날 수 있는 현상이다. 해당 쿼리로 읽히는 데이터에 들어가는 행이 새로 생기거나 없어지는 현상이다.

④ SERIALIZABLE

  • 격리 수준이 가장 높다
  • 한 트랜잭션에서 사용하는 데이터를 다른 트랜잭션에서는 접근 불가
  • 트랜잭션의 ACID 성질이 엄격하게 지켜지나 성능은 가장 떨어짐
  • 단순 SELECT 만으로도 트랜잭션이 커밋될 때까지 모든 데이터에 잠금이 설정되어 다른 트랜잭션에서 해당 데이터를 변경할 수 없게 된다.
Dirty ReadNon-Repeatable ReadPahntom Read
READ_UNCOMMITTED
READ_COMMITTED
REPEATABLE_READ
SERIALIZABLE

0개의 댓글