48. Node.js 심화주차 - 트랜젝션 (항해 24일차)

코이그·2023년 4월 26일

항해99

목록 보기
46/54

트랜젝션

특정 작업을 전부 처리 / 실패하게 만들어 데이터의 일관성을 보장해주는 기능

why?

  • 여러 개의 작업을 묶어서 하나의 작업 단위로 그룹화 후 처리 가능
  • 부분 업데이트 방지

특징

ACID:

  1. Atomicity(원자성)
    • 동시에 실행되는 명령들을 하나로 묶어 전부 성공 혹은 전부 실패해야함.
  2. Consistency(일관성)
    • 트랜젝션 내부에서 처리되는 데이터는 일관되어야함.
    • 성공-문제x, 실패-실패하더라도 문제 발생x.
  3. Isolation(격리성)
    • 외부에서 트랜젝션 진행 전/후 데이터 참조 가능.
    • 외부에서 트랜젝션 진행 도중 데이터 참조 불가능.
  4. Durability(지속성)
    • 하나의 데이터를 여러 명의 사용자가 동시 사용/공유 가능.

예제

CREATE TABLE IF NOT EXISTS SPARTA
(
    spartaId      INT(11)      NOT NULL PRIMARY KEY AUTO_INCREMENT,
    spartaName    VARCHAR(255) NOT NULL,
    spartaAddress VARCHAR(255) NOT NULL
);

START TRANSACTION;
INSERT INTO SPARTA (spartaName, spartaAddress)
VALUES ('SPARTA1', 'SEOUL'),
       ('SPARTA2', 'BUSAN'),
       ('SPARTA3', 'DAEGU');
COMMIT;

START TRANSACTION;
INSERT INTO SPARTA (spartaName, spartaAddress)
VALUES ('SPARTA4', 'SEOUL'),
       ('SPARTA5', 'BUSAN'),
       ('SPARTA6', 'DAEGU');
ROLLBACK;
  1. 첫 번째 트랜젝션은 COMMIT 되었기 때문에 데이터 추가
  2. 두 번째 트랜젝션은 ROLLBACK 되었기 때문에 데이터 추가 x (작업되기 전 상태)

Lock

동시성을 제어하는 기능
해당 데이터를 점유해서 다른 트랜젝션의 접근을 막음.

종류

공유 락(shared lock)

aka 읽기 락(read lock)

  • 다른 트랜젝션의 데이터 조회 허용 / 수정 금지.
  • 해당 lock을 사용하는 모든 작업이 완료되면 lock 해제.

배타 락(exclusive lock)

aka 쓰기 락(write lock)

  • 다른 트랜젝션의 데이터 읽기/수정 금지.
  • 점유된 데이터에 다른 트랜젝션의 접근 금지.

락킹 수준

글로벌 락

aka 데이터베이스 락

  • db의 모든 테이블에 lock을 걸어 모든 테이블로의 접근을 막음.

테이블 락

  • 테이블에 lock을 걸어 해당 테이블로의 접근만 막음.

네임드 락

  • 특정 문자열에 lock을 걸어서 접근을 막음.

메타데이터

동일 행/데이터베이스의 객체에 lock을 걸어 접근/수정을 막음.

교착 상태(Dead Lock)

여러 테이블에 lock이 걸려서 다른 작업이 처리되지 못하게 점유하고 있는 작업이 있을 때 다른 작업이 끝나는 것을 무한정 기다리는 상태.

트랜젝션의 격리 수준

여러 트랜젝션이 동시에 처리될 때 다른 트랜젝션에서 변경 및 조회하는 데이터를 읽을 수 있도록 허용/거부하는 것을 결정하기 위 사용.

READ UNCOMMITTED

  • 커밋되지 않은 읽기 허용 (작업 도중의 상태를 다른 트랜젝션이 참조 가능)
  • 가장 낮은 격리 수준
  • lock이 없으므로 동시성은 높지만 일관성이 깨질 수 있음.

READ COMMITTED

  • 커밋된 읽기만 허용 (작업 도중의 상태를 다른 트랜젝션이 참조 x)
  • select문이 실행될 때 공유 락을 검.

REPEATABLE READ

  • 트랜젝션이 완전히 종료될 때까지 lock 유지.
  • 수정은 불가능하지만 삽입은 가능함. (팬텀 읽기가 발생할 수 있음)
  • 팬텀 행: 트랜젝션 수행 중 다른 트랜젝션에 의해 삭제된 데이터
  • 팬텀 읽기: 팬텀 행에 해당하는 데이터 조회

SERIALIZABLE

  • 해당 데이터를 다른 트랜젝션이 읽기/삽입/수정 불가, 새로운 데이터 추가 불가.

sequelize - transaction

managed

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

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을 직접 호출해야한다.

격리 수준 설정

const { Transaction } = require("sequelize");

const t = await sequelize.transaction({
  isolationLevel: Transaction.ISOLATION_LEVELS.[
  READ_UNCOMMITTED | 
  READ_COMMITTED |
  REPEATABLEREAD |
  SERIALIZABLE
];

트랜젝션 객체를 생성할 때 isolationLevel 프로퍼티를 설정할 수 있다.

profile
COYG🔴⚪

0개의 댓글