트랜잭션이란?
- 작업의 완전성을 보장해주기 위해 사용되는 개념 특정한 작업을 전부 처리하거나 전부 실패하게 만들어 데이터의 일관성을 보장해주는 기능
- sql로 작성되는 여러 쿼리들을 1개의 단위로 묶어 하나의 작업으로 그룹화하여 처리함
- ex) 결제 시스템, 예매 시스템등에 적용
트랜잭션 사용이유
- 트랜잭션을 사용하면 항상 프로그램 실행을 완료하도록 구성함
- 만약 트랜잭션이 실패할 경우 오류가 발생하더라도 DB에 영향이 가지 않아 데이터를 안전하게 다룰 수 있음
트랜잭션 특징 4가지 (ACID)
원자성 Atomicity
- 트랜잭션 내에서 실행되는 명령어들을 하나의 묶음으로 처리하여, 내부에서 실행된 명령들이 전부 성공 하거나, 모두 실패해야 한다는 특징
- 여러개읨 작업들을 묶어 하나의 작업단위로 처리
- 하나의 함수처럼 트랜잭션 사용
- ex) 계좌이체 : a의 계좌에서 2000원 인출 a계좌 + 2000 + b의 계좌에 2000원 추가
일관성 Consistency
- 트랜잭션 내부에서 처리되는 데이터의 일관성을 유지해야하는 특징
- 작업이 성공할 경우 아무런 문제가 발생하지 않음, 실패하더라도 작업을 진행하던 도중 실패한 상태로 데이터를 방치하지 않는 특징
- 에러가 발생하더라도 DB에 저장된 데이터에 영향이 가지 않아야함
- 에러 발생시 ROLLBACK
격리성 Isolation
- 트랜잭션 수행전,후의 데이터를 외부에서 참조할 수 있지만 트랜잭션 실행중에는 데이터를 READ하거나 WRITE할 수 없도록 구성하는 특징
- MySQL에서 ㅅ용중인 DB오브젝트에 LOCK을 걸어 격리성 구현
- LOCK을 건 상태는 DB에 접속한 또다른 클라이언트가 해당하는 오브젝트를 읽거나, 사용할 수 없도록 만듬
동시성
- 여러명의 사용자가 하나의 데이터를 동시에 사용(READ, WRITE) 및 공유하는 것
- 동시성제어?
격리수준
READ UNCOMMITTED
- **커밋 되지 않은 읽기(Uncommitted Read)**를 허용하는 격리 수준입니다.
- 가장 낮은 수준의 격리수준이며, 락을 걸지 않아 동시성이 높지만 일관성이 쉽게 깨질 수 있습니다.
READ COMMITTED
- 커밋 된 읽기(Committed Read)만을 허용하고, SELECT 문을 실행할 때 공유락을 겁니다.
- 다른 트랜잭션이 데이터를 수정하고 있는 중에는 데이터를 읽을 수 없어 커밋되지 않은 읽기현상이 발생하지 않습니다.
REPEATABLE READ
- 읽기를 마치더라도 공유락을 풀지 않으며, 트랜잭션이 완전히 종료될 때 까지 락을 유지합니다.
- 공유락이 걸린 상태에서 데이터를 수정하는 것은 불가능하지만, 데이터를 삽입하는 것이 가능해집니다. 그로인해 팬텀 읽기가 발생할 수 있는 문제점이 있습니다.
SERIALIZABLE
- 데이터를 읽는 동안 다른 트랜잭션이 해당 데이터를 읽거나 삽입할 수 없고, 새로운 데이터를 추가하는 것 또한 불가능합니다.
- 가장 높은 수준의 격리 수준이므로, 동시성이 떨어지는 문제점이 존재합니다.
- 커밋되지 않은 읽기(Uncommitted Read)는 무엇일까요?
- 커밋되지 않은 읽기(Uncommitted Read)는 다른 트랜잭션에 의해 작업중인 데이터를 읽게 되는 것을 나타냅니다. 만약 커밋되지 않은 읽기가 발생할 경우, 의도치 않은 데이터를 참조하게 되어 데이터의 일관성이 깨지게 되는 상황이 발생하게됩니다.
- 팬텀 읽기(Phantom Read)란 무엇일까요?
- 트랜잭션을 수행하던 중 다른 트랜잭션에 의해 삭제된 데이터를 팬텀행(Phantom Rows)이라고 합니다. 여기서, 팬텀행에 해당하는 데이터를 읽는 것을 팬텀 읽기(Phantom Read)라고 부릅니다.
지속성 Durability
- 트랜잭션을 성공적을 수행하면 수정된 데이터를 DB에 영구적으로 적용하는 특징
- 트랜잭션의 중간결과가 아닌 완성된 결과만 저장하여 DB에 이상이 생기더라도 자동 복구할 수 있는 특성을 가짐
- 트랜잭션 완료이후 DB에 COMMIT 요청, 변경하상이 반영되기 전에 DB가 비정상적으로 종료될 경우 DB가 재시작 될때 트랜잭션의 변경사항을 다시 반영하게됨 => 지속성
SQL 트랜잭션 예시코드
-- SPARTA 테이블을 생성합니다.
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
);
-- 1번째 트랜잭션을 실행합니다.
START TRANSACTION;
-- SPARTA 테이블에 더미 데이터 3개를 삽입합니다.
INSERT INTO SPARTA (spartaName, spartaAddress)
VALUES ('SPARTA1', 'SEOUL'),
('SPARTA2', 'BUSAN'),
('SPARTA3', 'DAEGU');
-- 1번째 트랜잭션을 DB에 적용합니다.
COMMIT;
-- 2번째 트랜잭션을 실행합니다.
START TRANSACTION;
-- SPARTA 테이블에 더미 데이터 3개를 삽입합니다.
INSERT INTO SPARTA (spartaName, spartaAddress)
VALUES ('SPARTA4', 'SEOUL'),
('SPARTA5', 'BUSAN'),
('SPARTA6', 'DAEGU');
-- 2번째 트랜잭션을 롤백합니다.
ROLLBACK;
Sequelize 트랜잭션 예시코드
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 격리수준 설정
const { Transaction } = require("sequelize");
const t = await sequelize.transaction({
isolationLevel: Transaction.ISOLATION_LEVELS.READ_COMMITTED, // 트랜잭션 격리 수준을 설정합니다.
});
'DB, SQL' 카테고리의 다른 글
MySQL VIEW (0) | 2023.10.09 |
---|---|
MySQL 제약조건 (0) | 2023.10.08 |
MySQL JOIN (0) | 2023.10.03 |
MySQL 데이터 형식 (0) | 2023.10.02 |