#sql #node.js #tsql #sequelize.js
#sql #node.js #tsql #sequelize.js
Вопрос:
Допустим, мы внедрили пару (фиктивных) сервисов, использующих модели Sequelize для доступа к нашей БД:
export class AService {
// ... some other stuff
async updateSomeA(aId: number, value: string) {
let instanceA = await ModelA.findById(aId);
// need this update to use the transaction!
await instanceA.update({
some_field: value
});
}
}
export class BService {
// ... some other stuff
async updateB(bId: number, value: string) {
let instanceB = await ModelB.findById(bId);
// and this one as well!
await instanceB.update({
some_field_in_b: value
});
}
}
Теперь мы хотим вызвать updateSomeA
и updateB
из другого места в нашем коде, скажем, из CService
, но мы хотим, чтобы эти вызовы были включены в транзакцию.
class CService {
// ...stuff
async f() {
// == begin transaction
await AService.updateSomeA(1, 'blah!');
await BService.updateB(3, 'meh');
// == end transaction
}
}
Из того, что я собираю, просматривая документы, чтобы защитить код с помощью транзакции, мне нужно либо обернуть его в обратный вызов, либо использовать обещание. Это правильно?
Если это так, то я был бы вынужден модифицировать свои сервисы и, вероятно, иметь некоторые «транзакционные» версии моих методов, правильно?
Знаете ли вы, ребята, есть ли планы поддержки чего-то вроде
Transaction.begin("myAwesomeTransaction");
// ... every SQL generated in here is 'safe'
Transaction.end();
РЕДАКТИРОВАТЬ: решение «транзакция как аргумент»
Конечно, мы всегда можем использовать транзакцию в качестве необязательного последнего аргумента во всех наших сервисных функциях или, по крайней мере, в тех, которые имеют побочные эффекты (например deleteA
, updateB
, и т.д.). Что-то вроде:
// ... changed AService.updateSomeA
async updateSomeA(aId: number, value: string, t?: Sequelize.Transaction) {
let instanceA = await ModelA.findById(aId);
await instanceA.update({
some_field: value
}, {
transaction: t // we use the transaction if we get one
});
}
Но что происходит с нашим CService.f()
? Должна ли эта функция создавать транзакцию и передавать ее или ожидать транзакцию в качестве необязательного аргумента? Ну, ответ и то, и другое, не так ли? Если мы вызываем f()
из какой-либо другой службы как часть более крупной транзакции, мы ожидаем, что она получит этот Transaction
экземпляр и будет использовать его. С другой стороны, если мы вызываем f()
извне (например, контроллер), мы не хотим создавать транзакции там … верно ?!
Итак, мы получаем что-то вроде:
// ... changed CService.f
async f(t?: Sequelize.Transaction) {
if(!t) return sequelize.transaction(_f); // using the autoCallback overload
else return _f(t);
async function _f(trans: Sequelize.Transaction) {
// ... actual code for f() goes here
}
}
Идеально? Нет… С нетерпением ждем вашего вклада!
Комментарии:
1. Будет ли работать создание транзакции и добавление ее в сервисы? Поэтому вызывайте
update
транзакцию, если аргумент транзакции существует.2. @user3254198 Да, добавление дополнительного необязательного аргумента к каждой функции было именно тем, чего я пытался избежать, но…
3. Транзакции в
sequelize
разрешаются сpromises
помощью . Так что действительно, передача транзакции была бы правильным решением. Вы не хотите создавать эту транзакцию в своем контроллере, но когда она вам действительно понадобится. Не до и, конечно, не после. Но то, как вы хотите, чтобы это работало (например, определена глобальная транзакция, и это также запускает другие файлы), не будет работать сsequelize