데이터베이스 트랜젝션(Transaction) 개념정리

dO_the_Jeegu·2023년 4월 2일

개념정리

목록 보기
5/5

✔ 참고영상
🚩 [10분 테코톡] 🐤 샐리의 트랜잭션
🚩 데이터베이스 트랜잭션(transaction)을 아십니까?


1. Transaction이란?

  • A single logical unit of work
  • 논리적인 이유로 여러 SQL문을 단일 작업으로 묶어서 나눠질 수 없게 만든 것
  • 즉, 더이상 나눌 수 없는 가장 작은 하나의 단위
  • 데이터베이스에서는 트랜잭션을 조작함으로써 사용자가 데이터베이스에 대한 완전성을 신뢰할 수 있도록 함

예를 들어 은행 입출금 시스템을 생각해보자.

  1. 출금자가 만원을 이체한다고 할 때, 출금자의 계좌에 만원 이상의 금액이 있는지 확인
  2. 만원 이상이 있다는 것을 확인한 후 입금자에게 송금
  3. 출금자의 잔액은 만원 감소하며 입금자의 잔액은 만원 증가

이 일련의 업무는 분리되어서 안되며 일부만 실행되어서도 안된다. 이렇게 절대로 깨져서는 안되는 하나의 작업을 트랜잭션이라고 한다.

모든 데이터베이스는 자체적으로 트랜잭션을 지원하는데, 이는 하나의 명령을 실행했을 때 데이터베이스가 온전히 그 명령을 실행해주는 것을 의미한다. 데이터 베이스는 기본적으로 트랜잭션을 관리하기 위한 설정을 가지고 있다.

  • Redo log : 데이터베이스에 반영된 내용을 재반영하기 위한 기능
  • Undo log : 수행을 실패했을 때 이전의 상태로 되돌리는 기능

2. MySQL Transaction 예시

(1) 트랜잭션 성공 (J가 H에게 20만원을 송금하는 경우)

mysql> START TRANSACTION;
mysql> UPDATE account SET balance=balance-200000 WHERE id='J';
mysql> UPDATE account SET balance=balance+200000 WHERE id='H';
mysql> COMMIT
  • 트랜잭션 시작
  • J의 잔액에서 20만원 차감
  • H의 잔액에서 20만원 증가
  • COMMIT : 지금까지 작업한 내용을 DB에 영구적으로 저장 후 transaction 종료

(2) 트랜잭션 실패 (J가 H에게 30만원 송금하려다 중간에 오류가 발생한 경우)

mysql> START TRANSACTION;
mysql> UPDATE account SET balance=balance-300000 WHERE id='J';

// 오류 발생

mysql> ROLLBACK;
  • 트랜잭션 시작
  • J의 잔액에서 30만원 차감
  • 오류 발생
  • ROLLBACK : 지금까지 작업한 내용을 모두 취소하고 transaction 이전의 상태로 되돌린 후 trasaction 종료

✍ AUTOCOMMIT

: 각각의 SQL문을 자동으로 transction 처리해주는 개념. SQL문이 성공적으로 실행되면 자동으로 commit하고 실행 중에 문제가 발생하면 자동으로 rollback해준다. MySQL에서는 default로 autocommit 기능이 enabled 되어있는데, SATRT TRANSACTION 실행 시에는 자동으로 off된다. 이후 트랜잭션이 종료되면 원래 autocommit상태로 돌아간다.


3. Spring Transaction

데이터베이스에서는 각각의 명령을 하나의 트랜잭션으로 보고 보장하기 때문에 여러 명령을 하나의 트랜잭션으로 묶고 싶은 경우 개발자가 직접 트랜잭션의 경계설정을 통해 트랜잭션을 명시하는 작업이 필요하다.

Spring은 트랜잭션 경계 설정을 데이터베이스에 전달해주는 기능이 있는데, 트랜잭션 추상화 인터페이스인 PlatformTransactionManager를 제공한다.

public interface PlatformTransactionManager
extends TransactionManager {
	TransactionStatus getTransaction(@Nullable TransactionDefinition definition) throws TransactionException
	void commit(TransactionStatus status)
	void rollback(TransactionStatus status)
}
  • getTransaction 메서드를 통해 파라미터로 전달되는 transactionDefinition에 따라 트랜잭션을 시작
  • 트랜잭션을 문제 없이 마치면 commit 호출
  • 문제가 발생하면 rollback 호출

스프링이 제공하는 TransactionManager 구현체는 대표적으로 DataSourceTransactionManager, JpaTransactionManager, JtaTransactionManager 등이 있다.

이렇게 직접적으로 코드에 구현하는 방식 외에도 AOP를 이용한 선언적 트랜잭션을 제공하는데, 대표적인 예는 아래와 같다.

(1) TX Namespace
: Bean 설정파일에서 트랜잭션 매니저를 등록하고 속성과 대상을 정의해 트랜잭션을 적용하겠다고 명시하는 것. 코드에는 영향을 주지 않고 일괄적으로 트랜잭션을 적용하고 변경할 수 있다는 장점이 있다.

(2) 어노테이션 @Transactional
일반적으로 가장 많이 사용하는 방식. 트랜잭션 어노테이션은 메서드, 클래스, 인터페이스 등에 적용할 수 있다. 클래스 상단에 적용된 어노테이션에 대해서는 해당 클래스에 존재하는 모든 메서드에 어노테이션이 적용된다. 세밀한 설정을 할 수 있다는 장점이 있다.

  • 중첩되는 경우 : 클래스 메서드 > 클래스 > 인터페이스 메서드 > 인터페이스 순으로 우선순위 적용

4. Transaction ACID

트랜잭션은 네 가지 성질(ACID)를 바탕으로 신뢰를 보장한다.

  1. 원자성(Atomicity) : 하나의 트랜잭션은 작업의 일부가 실패할 경우 전체 작업이 실패되어야 한다. 즉, 트랜잭션 내 모든 작업은 전부 성공 혹은 전부 실패해야 한다.
    • 만약 1, 2 성공 후 3이 실패한다면 rollback을 통해 앞에 성공했던 것들도 모두 없었던 일처럼 되돌린다.
    • 1, 2, 3 모두 성공했다면 commit을 통해 수정된 내용을 데이터베이스에 반영한다.
    • 트랜잭션은 Rollback 또는 Commit이 수행되어야 종료된다.
  1. 일관성(Consistency) : 트랜잭션을 수행하기 전후로 데이터베이스 상태(데이터베이스 내의 계층관계, 컬럼의 속성 등)는 일관성이 있어야 한다.
    • 이체 시스템 설계 시 계좌 잔액이 0원보다 크거나 같아야 한다는 조건은 필수다. 이런 전제조건을 두고, 만약 A의 계좌에 80만원이 있는데 100만원을 이체한다고 해보자. 이는 일관성을 깨드리는 작업이므로 실패할 것이다.
  1. 격리성(Isolation) : 여러 개의 트랜잭션이 동시에 수행되더라도 각각의 트랜잭션은 다른 트랜잭션과 독립적으로 실행되어야 한다. 다른 트랜잭션에서 수행하는 작업에 대해 영향을 받지 않아야 한다.
    • 만약 A와 B가 동시에 C에게 만원을 송금했을 때 B의 잔액이 동일하게 0원으로 조회되는 경우 C의 최종 잔액이 2만원이 아닌 만원이 될 수 있다.
    • 트랜잭션은 격리 수준 설정을 통한 독립성 보장으로 이런 경우를 방지한다. 다만, 엄격하게 구현할 경우 DB 성능이 저하될 수 있으므로 여러 종류의 Isolation level로 나누어 구현한다.
  1. 지속성(Durability) : 트랜잭션이 성공적으로 완료(commit)된 후에는 그 결과가 데이터베이스에 반영되어야 하며, 시스템이 다운되거나 데이터베이스에 장애가 발생하더라도 결과는 유지되어야 한다.
    • 이를 위해 모든 트랜잭션은 로그로 남겨 어떠한 장애에도 대비할 수 있도록 한다.

❗ 기억하기

  1. 트랜잭션을 어떻게 정의해서 쓸 지는 개발자가 정하는 것이다.
    ⇒ 구현하려는 기능과 ACID 속성을 제대로 이해해야 트랜잭션을 잘 정의할 수 있다.

  2. DBMS가 모든 ACID를 보장해주지는 않는다.
    ⇒ Defalut 설정이 있긴 하지만 모든 것을 알아서 처리해주는 것은 아니기 때문에 상황에 따라서는 개발자가 따로 설정해야 하는 부분이 있다.
profile
오지는 갓생 살기

0개의 댓글