gpt4 book ai didi

mysql - 使用 sequelize.js 在 2 个表之间嵌套 mysql 事务

转载 作者:可可西里 更新时间:2023-11-01 07:30:32 26 4
gpt4 key购买 nike

我有 2 个 Sequelize 模型(与 2 个表关联的事件和库存)。我创建了一个 Event._create 方法,以便我可以使用它在事件数据库中创建一个事件,同时在库存数据库中记录多个产品。每个 list 都与新创建事件的 event_id 相关联。

因为所有这些东西都应该成功或完全失败,所以我使用 sequelize 的事务来实现这一点。

最初我想做这样的事情。

sequelize.transactionPromise = Promise.promisify(sequelize.transaction, sequelize);

return sequelize.transactionPromise({autocommit: 0})
.then(function(t) {
return Event.create(ev, {transaction: t})
.then(function(event){
var event_id = event.id; // ------ (*)
return Promise.resolve([1, ..., event_number])
.then(function(){
Inventory.create({product_id: some_product_id, event_id: event_id},
{transaction: t});
});
.then(function(){
return Promise.cast(t.commit())
.then(function() { // successfully committed
return res.json(d);
}).catch(function(err){ // cannot commit somehow
return res.json(500, err.toString());
});
}).catch(function(err){ // error rollback
return Promise.cast(t.rollback())
.then(function() {
return Promise.reject('rollback: ' + err.toString());
});
});
});

但这行不通,因为在提交事务之前,(*) 没有任何值并且给我的 event_id 为 NULL。

相反,我会执行如下操作:

var Event = sequelize.model('Event'); 
var Inventory = sequelize.model('Inventory');

var _create = function(t, ev){
var ev_id_secret = {secret: 'some random secret'};
return Promise.cast(Event.create(ev_id_secret))
.then(function(d){
ev_id_secret.id = d.id;
return true;
}).then(function(){
return Promise.resolve(_.range(ev.number_of_products))
.map(function(){
var inventory = {
event_id: ev_id_secret.id,
product_id: ev.product_id
};
return Promise.cast(Inventory._create(t, inventory));
});
}).then(function(){ // thennable a transaction
return Promise.cast(Event.update(ev, ev_id_secret, {transaction: t}));
});
};

所以我可以做这样的事情。

sequelize.transactionPromise=Promise.promisify(sequelize.transaction, sequelize); 
return sequelize.transactionPromise({autocommit: 0})
.then(function(t) {
return Event._create(t, ev)
.then(function(){
return Promise.cast(t.commit())
.then(function() {
return res.json(d);
}).catch(function(err){
return res.json(500, err.toString());
});
}).catch(function(err){
return Promise.cast(t.rollback())
.then(function() {
return Promise.reject('rollback: ' + err.toString());
});
});
}).catch(function(err){
console.log(err.stack);
res.json(500, {error: err.toString()});
});

我对 _create 所做的是,我只是在事件数据库中插入一个空事件(具有随机生成的 secret ),并在库存数据库中插入一些空产品,稍后使用此 secret 获取 event_id 以查询,相应地更新事件和库存。

事情是当 promise 被拒绝时,事务回滚()被调用并在数据库中留下空的事件和产品记录。所以我必须稍后处理空记录,这真的很令人不安。

所以我的问题是如何正确地在 2 个表之间进行交易?我在正确的轨道上吗?

p.s:作为附带问题,您可以看到我的代码充满了 return Promise.xxx 语句,这确保了控制流,但 promise 变得非常困惑。我可以做些什么来改进我的代码吗?谢谢。

最佳答案

您最初的实现是正确的。但是,在您创建事件之后,该对象应该返回时已经填充了 id 而无需提交(我假设您使用的是标准的自动递增 Sequelize id)。所有 SQL 数据库都以这种方式运行。我建议调试您的应用程序以确定问题的根源。

这是我的一个应用程序中的 sequelize 事务的示例实现。我刚刚测试并确认调用 db.Deposit.create() 解析为具有有效 ID 的对象。我正在使用 Bluebird、Sequelize 2.0.0-rc2 和 Postgresql 9.3

module.exports.createDeposit = function(deposit) {
return db.sequelize.transaction({isolationLevel: 'READ COMMITTED' })
.then(function(t){
var strQuery = 'UPDATE "Accounts" '
+ 'SET "balance"="balance" + :amount, "updatedAt"=NOW() '
+ 'WHERE "id"= :AccountId RETURNING *';

return sql.query(strQuery,
db.Account.build(),
{ raw: true, transaction : t },
{ AccountId: deposit.AccountId, amount: deposit.amount })

.then(function(account){
if (!account) throw new Error('Account does not exist')
return db.Deposit.create(deposit, { transaction: t });
})
.then(function(dbDeposit){
// If successful, dbDeposit object contains a valid id
if (!dbDeposit) throw new Error('Failed to create deposit');
return t.commit()
.then(function(){
return dbDeposit;
});
})
.catch(function(e){
return t.rollback()
.then(function(){
throw e;
});
});
});
};

关于mysql - 使用 sequelize.js 在 2 个表之间嵌套 mysql 事务,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27927360/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com