일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |
- TypeScript
- AWS
- Nest.js
- nestjs
- MySQL
- game
- typeORM
- Sequelize
- MongoDB
- Python
- 정렬
- GIT
- 공룡게임
- Dinosaur
- 게임
- flask
- Queue
- nodejs
- jest
- cookie
- mongoose
- class
- Express
- 자료구조
- OCR
- react
- JavaScript
- dfs
- Bull
- Today
- Total
포시코딩
1월19일 - Sequelize Transaction 본문
Sequelize Transaction 다루기
팀스터디 중에 트랜잭션 관련해서 추가로 나한테 주어진 과제가 있었다.
- repository에서 구현한 transaction 로직을 각각의 repo method를 구분지어 service에서 구현할 수 없을까
- Error message의 성격별로 status code를 구분지어 리턴하는 방법
- 트랜잭션 level? 전파?에 대해 알아보고 적용하는 방법
repo가 아닌 service에서 transaction 구현
일단 기존에 repo에서 성공적으로 transactiond을 구현했기 때문에
바로 떠오르는 아이디어가 있었다.
repo에서 했던대로 service에서 transaction 객체를 호출한 뒤 repo method를 호출할 때
파라미터로 넘겨 transaction 안에 포함시켜 버리는 것이었다.
변경 후 코드
orders.repository.js
createOrder = async (transaction, { ownerId, kinds, details, pickup, imageUrl }) => {
await this.ordersModel.create(
{
ownerId, kinds, details, pickup, imageUrl
},
{ transaction }
);
};
deductPoint = async (transaction, ownerId, transferPoint) => {
const userInfo = await this.usersModel.findOne(
{
attributes: ['id', 'point'],
where: { id: ownerId },
},
{ transaction }
);
if (!userInfo) {
const err = new Error('유저가 존재하지 않습니다.');
throw err;
}
userInfo.point -= transferPoint;
if (userInfo.point < 0) {
throw new Error('유저의 포인트가 부족합니다.');
}
await userInfo.save({ transaction });
};
orders.service.js
const { sequelize } = require('../sequelize/models/index');
// ...생략
createOrder = async (ownerId, kinds, details, pickup, imageUrl) => {
const transaction = await sequelize.transaction();
try {
// ...생략
await this.ordersRepository.createOrder(transaction, { ownerId, kinds, details, pickup, imageUrl });
const transferPoint = parseInt(process.env.ORDER_PRICE);
await this.ordersRepository.deductPoint(transaction, ownerId, transferPoint);
await transaction.commit();
SocketManager.alertNewOrder();
return { code: 201, message: '주문에 성공하였습니다.' };
} catch (err) {
await transaction.rollback();
return { code: 403, message: err.message };
}
};
예상했던대로 잘 작동하는걸 볼 수 있었다. 해결
상황별 Error에 따른 Status code 구분짓기
현재 코드에서 전달하는 Error.message를 어떤식으로 구분지어야할지 감이 안잡히고 있었는데
다른 팀의 프로젝트 코드를 리뷰하다가 아이디어를 얻었다.
new Error(); 로 생성한 객체의 멤버 변수 message처럼 name에도 똑같이 string을 부여할 수 있었다.
즉시 테스트
orders.repository.js
// ...생략
if (userInfo.point < 0) {
const err = new Error('유저의 포인트가 부족합니다.');
console.log('repo:: ');
console.log(err.name);
err.name = 'notEnoughPointError'
console.log(err.name);
throw err
}
// ...생략
orders.service.js
// ...생략
} catch (err) {
await transaction.rollback();
console.log('service:: ');
console.log(err.name);
return { code: 403, message: err.message };
}
console
repo에서 직접 부여한 Error.name을 service에서 전달받을 수 있다는게 확인되었음으로
Error.name에 대해 if문으로 status code를 구분 지을 수 있음을 알 수 있다. 이것도 해결
Propagation(전파 속성), Isolation Level(격리 수준 레벨)
Transaction level에 대해 한국말로는 전파라고 명칭하는줄 알았는데
좀 찾아보니 아예 다른 개념이었다.
Isolation(격리 수준 레벨)
Sequelize의 Isolation은 일반적인 SQL의 Isolation과 동일하게 동작한다.
SQL의 Isolation 격리 수준 속성은 다음과 같다.
= Transaction에서 일관성 없는 데이털르 허용하는 수준
Isolation Level은 네종류가 있다.
- Read Uncommitted
- Read Commited
- Repeatable Read
- Serializable
더 자세한건 아래 링크 참고
https://developyo.tistory.com/236?category=688590
Propagation(전파 속성)
여러 트랜잭션의 적용 범위를 묶어 커다란 하나의 트랜잭션 경계를 만들거나 할 수 있는데,
해당 트랜잭션에 대해 어떻게 진행시킬지를 전파 속성을 통해 결정한다.
transaction propagation 관련 검색을 하면 죄다 Spring에 대해서만 나오고
정작 Sequelize 공식 문서에도 Isolation Level 말고는 나오질 않아
일단 이정도 알게 되는 선에서 그치고
마침 따로 DB 관련해서 튜터님이 알려주시는게 있기 때문에 나중에 물어보기로 했다.
마치며
그냥 trasaction을 적용하기 까지는 너무 쉽다 생각했는데
역시 그에 관련해서 더 여러가지 고려해야될게 많다는걸 알게 되었고
심화 개념으로 갈수록 정보를 얻기도, 그 옵션 중 어떤걸 적용할지 어떻게 적용할지 모두 어려워지는걸 느꼈다.
그래도 DB 종류가 다름에도 전파 속성과 격리 수준 레벨에 대한 개념은 모두 비슷비슷하게 가지고 있기 때문에
검색해보면 관련 정보들을 얻기 수월해서 어느정도의 기본 개념은 잡게 된 것 같다.
참고한 곳
https://developyo.tistory.com/250
https://velog.io/@denhur62/트랜잭션-격리-수준과-전파-수준-그리고-읽기-수준
https://velog.io/@myspy/Transaction-전파가-뭡니까
https://nesoy.github.io/articles/2019-05/Database-Transaction-isolation
'TIL' 카테고리의 다른 글
1월21일 - TypeScript 기본 세팅 (0) | 2023.01.21 |
---|---|
1월20일 - 오버로딩(overloading) (0) | 2023.01.20 |
1월18일 - reversed, map (0) | 2023.01.18 |
1월17일 (0) | 2023.01.18 |
1월16일 - session, jwt, OAuth (0) | 2023.01.16 |