오늘은 트랜젝션의 격리 수준 및
프리즈마에서 사용법을 알아보겠다.
🏞️ 트랜잭션의 격리 수준 _ Isolation Level
- 여러 트랜젝션이 동시에 처리될 때 다른 트랜젝션에서 변경 및 조회하는 데이터를 읽을 수 있도록 허용/거부 를 결정하기 위해 사용.
- 즉 데이터의 일관성과 동시성 처리 성능 사이에 균형을 잡는것.
- READ UNCOMMITTED
- 커밋되지 않은 읽기를 허용함.
- 다른 트랜잭션에 의해 작업중인 데이터를 읽게 되는 것을 말한다..
- 가장 낮은수준의 격리.
- 락을 걸지 않아 동시성은 높으나
- 데이터 일관성이 쉽게 깨질수 있음.
- 의도치 않은 데이터를 참조하게 되어 데이터의 일관성이 깨지게 되는 상황이 발생하게 된다.
- READ COMMITED
- 커밋된 읽기만 허용
- select문 실행시 공유락 건다.
- 다른 트랜젝션이 데이터를 수정하고 있는 중에, 데이터를 읽을 수 없어 커밋되지 않은 읽기 현상이 발생하지 않는다.
- REPEATABLE READ
- 읽기를 마쳐도 공유락 안품.
- 트랜잭션 종료시까지 락을 유지
- 공유락이 걸린 상태에서 데이터 수정 불가 그러나 삽입은 가능
- 팬텀 읽기 발생할 수도 있다는 문제 발생.
- 팬텀읽기란
- 트랜잭션을 수행하던 중 다른 트랜잭션에 의해 삭제된 데이터를 팬텀행(Phantom Rows)이라고 한다.
- 여기서, 팬텀행에 해당하는 데이터를 읽는 것을 팬텀 읽기(Phantom Read)라고 함.
- SERIALIZABLE
- 데이터를 읽는 동안 다른 트랜잭션이 해당 데이터를 읽거나 삽입할 수 없다ㅏ.
- 새로운 데이터를 추가하는것 또한 불가능
- 가장 높은 수준의 격리 수준.
- 동시성이 떨어지는 문제점 존재.
🔮 Prisma Transaction
1. Sequential 트랜젝션
2. Interactive 트랜젝션
이렇게 나눠서 살펴보자.
1. Sequential 트랜젝션
- 배열 형태이며, 순차적 실행된다.
- 여러개의 쿼리를 하나의 트랜젝션으로 수행할 수 있는 Sequential 트랜젝션
import { PrismaClient } from '@prisma/client';
const prisma = new PrismaClient();
// Sequential 트랜잭션은 순차적으로 실행됩니다.
// 결과값은 각 쿼리의 순서대로 배열에 담겨 반환됩니다.
const [posts, comments] = await prisma.$transaction([
prisma.posts.findMany(),
prisma.comments.findMany(),
]);
혹은 로우쿼리로도 사용이 가능하다.
import { PrismaClient } from '@prisma/client';
const prisma = new PrismaClient();
// Sequential 트랜잭션은 순차적으로 실행됩니다.
// Raw Quyery를 이용하여, 트랜잭션을 실행할 수 있습니다.
const [users, userInfos] = await prisma.$transaction([
prisma.$queryRaw`SELECT * FROM Users`,
prisma.$queryRaw`SELECT * FROM UserInfos`,
]);
2. Interactive 트랜젝션
- 자체적으로 트랜잭션의 성공과 실패를 관리하는 interactive 트랜잭션
- 여기서 tx 라는 인자가 있는데, prisma 인스턴스 처럼 사용. 같은 기능임.
- 모든 비지니스 로직이 성공적으로 완료되거나 에러가 발생한 경우 Prisma 자체적으로 COMMIT 또는 ROLLBACK 을 실행.
- 에러 발생시 자동 롤백 기능이 있음. 완전 굿
- 트랜잭션을 관리하는 장점을 가지고 있다.
- 또한 트랜잭션 진행중에도 비지니스 로직 처리 가능. 복잡한 쿼리 시나리오 효과적 구현.
import { PrismaClient } from '@prisma/client';
const prisma = new PrismaClient();
// Prisma의 Interactive 트랜잭션을 실행합니다.
const result = await prisma.$transaction(async (tx) => {
// 트랜잭션 내에서 사용자를 생성합니다.
const user = await tx.users.create({
data: {
email: 'testuser@gmail.com',
password: 'aaaa4321',
},
});
// 에러가 발생하여, 트랜잭션 내에서 실행된 모든 쿼리가 롤백됩니다.
throw new Error('트랜잭션 실패!');
return user;
});
'TIL' 카테고리의 다른 글
23/12/04 TIL __ 테스트 코드(Jest) (0) | 2023.12.04 |
---|---|
23/12/03 TIL __ 3계층 아키텍쳐 (0) | 2023.12.03 |
23/12/01 TIL __ 트랜잭션 2. LOCKS (0) | 2023.12.01 |
23/11/30 TIL __ prisma 에서 테이블 조인하기 (0) | 2023.12.01 |
23/11/29 TIL __ prisma 사용하기 (0) | 2023.11.30 |