【发布时间】:2015-01-13 16:54:47
【问题描述】:
我有 2 个续集模型(与 2 个表关联的事件和库存)。我创建了一个 Event._create 方法,以便我可以使用它在事件数据库中创建一个事件,同时在库存数据库中记录多个产品。每个库存都与新创建事件的 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 所做的只是在 Event db 中插入一个空事件(具有随机生成的秘密),在 Inventory db 中插入一些空产品,然后使用此秘密获取 event_id 来查询、相应地更新事件和库存。
当 promise 被拒绝时,事务 rollback() 被调用并在数据库中留下空的事件和产品记录。所以我必须稍后处理空记录,这真的很烦人。
所以我的问题是如何正确地在 2 个表之间进行事务处理?我在正确的轨道上吗?
p.s:作为一个附带问题,您可以看到我的代码充满了 return Promise.xxx 语句,这确保了控制流,但承诺变得非常混乱。我可以做些什么来改进我的代码吗?谢谢。
【问题讨论】:
-
您使用的是哪个承诺库?另外,您能否发布所有代码,包括外部承诺包装器?
-
承诺是 bluebird.js。 mysql ORM 是 sequelize.js
标签: mysql database transactions promise sequelize.js