[TIL] Transaction 23.07.07

이상훈·2023년 7월 9일
0

[내일배움캠프]

목록 보기
41/68

트랜잭션이란?

데이터베이스의 상태를 변화시키기 위해 수행하는 작업의 단위를 뜻한다.
작업의 완전성을 보장해주기 위해 사용되는 개념이며, 특정한 작업을 전부 처리하거나,
전부 실패하게 만들어 데이터의 일관성을 보장해준다.
데이터베이스의 상태를 변화시킨다는 의미는 질의어(SELECT, INSERT, DELETE, UPDATE)를 이용하여 데이터베이스에 접근하는 것을 의미한다.

트랜잭션을 사용해야 하는 이유

1) A가 B에게 1,000원을 계좌이체 하려함
2) 송금 중 알 수 없는 이유로 A의 계좌에서 돈은 빠져나갔지만 B에게는 입금되지 않음
-> A의 계좌에서 1,000원만 차감되는 문제가 발생하게 된다. 이러한 상황을 막기 위해 거래가 모두 끝나야 완전한 거래로 Commit하고, 유로가 발생했을 시 Rollback을 통해 시작 전으로 되돌려야 한다.

Commit
-> 하나의 트랜잭션이 성공적으로 끝나 데이터베이스가 일관성 있는 상태에 있음을 의미
Rollback
-> 트랜잭션 처리가 비정상적으로 종료되어 원자성이 깨진 상태를 의미, 원자성을 지키기 위해 트랜잭션이 행한 모든 연산을 재시작하거나 취소함

트랜잭션의 특징(ACID)


1) 원자성(Atomicity)

  • 트랜잭션 내에서 실행되는 명령들을 하나의 묶음으로 처리
  • 내부에서 실행된 명령들이 전부 성공하거나, 아니면 모두 실패해야함
  • 트랜잭션의 연산은 모두 반영되도록 Commit 되거나 전혀 반영되지 않도록 Rollback 되어야 함
    2) 일관성(Consistency)
  • 트랜잭션 내부에서 처리되는 데이터의 일관성을 유지해야함
  • 작업이 성공할 경우 아무 문제가 발생하지 않고, 실패하더라도 작업을 진행하던 도중 실패한 상태로 데이터를 방치하지 않음 (Rollback)
    3) 격리성(Isolation)
  • 트랜잭션 수행 시 다른 트랜잭션 연산에 끼어들지 못하도록 보장
  • 수행 중인 트랜잭션은 완전히 완료될 때까지 다른 트랜잭션에서의 수행 결과를 참조할 수 없음
    -> 동시성(Concurrency)과 격리 수준(Isolation Level)이라는 개념이 나타남
    -> Sequelize에서 격리수준 설정 방법
const { Transaction } = require("sequelize");

const t = await sequelize.transaction({
  isolationLevel: Transaction.ISOLATION_LEVELS.READ_COMMITTED});

4) 지속성(Durability)

  • 트랜잭션을 성공적으로 수행하면 수정된 데이터를 시스템에 영구적으로 적용
  • 중간 결과가 아니라 완성된 결과만 저장하여 데이터베이스에 이상이 생기더라도 자동 복구할 수 있음

Managed Transaction

const { sequelize } = require("../models/index.js");

// 콜백으로 함수를 할당하여 비즈니스로직을 처리
const result = await sequelize.transaction( async(t) => {
  const user = await User.create({
    firstName: '예시',
    lastName: '예시',
  }, { transaction: t }); // 해당 쿼리에 트랜잭션을 적용

  return user;
});

-> 모든 비즈니스 로직이 성공하거나 에러가 발생한 경우 Sequelize 자체적으로 Commit과 Rollback을 하는 장점이 있음

UnManaged Transaction

const { sequelize } = require("../models/index.js");

// Sequelize의 트랜잭션을 변수에 할당하여 트랜잭션을 시작
const t = await sequelize.transaction();

try {
  const user = await User.create({
    firstName: '예시',
    lastName: '예시',
  }, { transaction: t }); // 해당 쿼리에 트랜잭션을 적용

  // 트랜잭션을 사용한 모든 로직을 Commit, DB에 반영
  await t.commit();
} catch(transactionError) {
  // 에러가 발생하였다면, 트랜잭션을 사용한 모든 쿼리를 Rollback, DB에 반영하지 않음
  await t.rollback();
}

명시적으로 트랜잭션을 관리하기 때문에, 관리 현황을 명확하게 알 수 있고 원하는 분기처리를 간단하게 구분할 수 있어 비즈니스로직을 있는 그대로 코드로 나타내기 쉬움
Commit과 Rollback을 실행해야만 트랜잭션을 종료할 수 있음

profile
코린이

0개의 댓글