결제 기능에서 보유포인트보다 물건의 포인트가 작으면 결제가 되게끔 로직을 구현함에 있어서 트랜잭션의 필요성을 느끼게 되었다. 이런가능성 저런가능성을 생각하다보니 아 이래서 트랜잭션을 쓰는구나 싶었다. 우리는 결제와 잔여 포인트 감소를 원자적으로 처리해서 중간단계에서 실패하더라도 일관성있게 롤백하는 기능이 우선적으로 필요했다. 또한 여러 사용자가 동시에 잔여 포인트를 변경하려고 할때도 충돌을 방지하고 데이터의 정확성을 보장해야했다. 결론적으로 트랜잭션을 통해 변화가 모두 적용되거나 , 모두 적용되지 않게 되기 때문에 지속성도 보장이되고 정확히 빠진 금액이 보장되기 때문에 왜 모두가 트랜잭션을 결제기능에서 꼭 사용했는지 이해가 되었다.
그래서 트랜잭션을 사용하려 하는데 ..
기존에 한 파일내에서 다 끝내는 방식으로 하는것이 아니고 controller , service , repository 3계층으로 나누려다보니 이상하게 생각대로 안됐다.
우선 에러가 난 코드를 먼저 보자
// repository
updatepoint = async (custoMeruserPoint, menuPoints, userId) => {
try {
await sequelize.transaction(async t => {
if (custoMeruserPoint >= menuPoints) {
const usermenupoint = custoMeruserPoint - menuPoints;
const ppoint = await Users.update(
{
point: usermenupoint,
},
{ where: { userId } },
{ transaction: t }
);
return ppoint;
//사장님 돈도 더해주자 !
}
});
} catch (transactionError) {
console.log(transactionError);
}
};
로직 순서는 ,
1. 손님의 point 조회
2. 손님의 장바구니 속 manu 들의 각 각 point 들을 다 더한 totalPoint 구하고
3. 손님의 잔액이 부족하지 않다면 , 1번에서 2번을 빼준 값을 구하고
4. 빼준값을 손님의 user 테이블에 업데이트 해준다
5. 그 후에 그 돈을 사장님의 point에 추가해준다
이런 순서로 진행되는데 과제 필수구현이 트랜잭션이였다
우리는 3번부터 5번까지를 트랜잭션으로 묶어 한번에 진행하고 싶고 , 에러가 난다면 모두 롤백하는 기능으로 만들고 싶다
근데 트랜잭션이 이상한 에러를 내기 시작했다
Cannot read properties of undefined (reading 'transaction')
트랜잭션 속성에 접근하면서 생긴 문제거나 , 패키지를 임포트 하지 않았을대 생긴다는데
우선 패키지는 잘 임포트 하였다 ..
const { Op, Transaction, sequelize } = require('sequelize');
그래서 트랜잭션을 부를때
이렇게 했더니 ....
Class constructor Transaction cannot be invoked without 'new'
이번엔 이런 에러가 났다
너가 이기나 내가 이기나 해보자
로 바꿔줬더니
Cannot read properties of undefined (reading 'queryGenerator')
결국 공식문서부터 천천히 봤다.
결국 찾아낸거
const { sequelize } = require('../models');
우리는 시퀄라이저 패키지 안에 있는 트랜잭션이라는 기능을 사용하는걸로 알고
const {sequelize} = require('sequelize') 로 했었는데
기존에 우리가 DB와 연결해둔 시퀄라이저에서 트랜잭션을 하는거니까 그 시퀄라이저를 가져와야했던것 !
DB에 연결되어있는 시퀄라이저를 가져와야 했던것이다
참고용으로 우리가 DB와 연결한 sequelize 부분을 첨부하고 끝내겠다
'use strict';
const fs = require('fs');
const path = require('path');
const Sequelize = require('sequelize');
const process = require('process');
const basename = path.basename(__filename);
const env = process.env.NODE_ENV || 'development';
const config = require(__dirname + '/../config/config.js')[env];
const db = {};
let sequelize;
if (config.use_env_variable) {
sequelize = new Sequelize(process.env[config.use_env_variable], config);
} else {
sequelize = new Sequelize(
config.database,
config.username,
config.password,
config
);
}
fs.readdirSync(__dirname)
.filter(file => {
return (
file.indexOf('.') !== 0 &&
file !== basename &&
file.slice(-3) === '.js' &&
file.indexOf('.test.js') === -1
);
})
.forEach(file => {
const model = require(path.join(__dirname, file))(
sequelize,
Sequelize.DataTypes
);
db[model.name] = model;
});
Object.keys(db).forEach(modelName => {
if (db[modelName].associate) {
db[modelName].associate(db);
}
});
db.sequelize = sequelize;
db.Sequelize = Sequelize;
module.exports = db;
결론 ! 트랜잭션 쓸때
const {sequelize} = require("../models")
쓰자 !@@
'Node.js' 카테고리의 다른 글
node.js) 소셜 로그인 (카카오톡) / 토큰 재발행 , 회원가입 저장 (0) | 2023.09.07 |
---|---|
node.js) 소셜 로그인 (카카오톡) / 토큰 재발행 , 회원가입 저장 (0) | 2023.08.24 |
(TIL)node.js 좀 더 좋은 코드 고민 : 서버 객체화 하기 (0) | 2023.07.27 |
js)import require 에러 모음집 .... (0) | 2023.07.27 |