Bookshelf.js - 交易的意外行为
Bookshelf.js - unexpected behaviour with transactions
我已经看了好几天了,我还不能得出任何合理的解释。因此,简要介绍一下背景:我正在使用 bookshelfjs,我想使用事务来执行 3 次插入,并在保存时添加一些额外的引用。为了让事情按照我希望的方式工作,我使用了 bluebird Promise。
router.get('/transaction', function(req, res){
bookshelf.transaction(function(t){
return Promise.all([
//this block is part of transaction!
new Participant({name: 'Transaction John'}).save(null, {transacting: t}),
new Participant({name: 'Transaction Doe'}).save(null, {transacting: t}),
new Town({town_number: 1000, town_title: 'LA'}).save(null, {transacting: t})
]).spread(function(p1, p2, t1){
return Promise.all([
/*
this block, however, is not. second address save fails, because I use "p4.get('id')" which does not exists
the first address is saved, the second is not; but since I use transactions, nothing should be saved!
*/
new Address({
house_number: 3,
street_name: 'Transaction street name',
town_id: t1.get('id'),
participant_id: p1.get('id')
}).save(null, {transacting: t}),
new Address({
house_number: 3,
street_name: 'Transaction street name 2',
town_id: t1.get('id'),
participant_id: p4.get('id')
}).save(null, {transacting: t})
]);
});
}).then(function(){
res.json('success');
}).catch(function(error){
console.log('error');
res.json(error);
});
});
以上代码的查询如下:
{ __cid: '__cid1', sql: 'begin transaction;' }
{ __cid: '__cid1',
method: 'insert',
options: undefined,
bindings: [ 'Transaction John' ],
sql: 'insert into "participants" ("name") values (?)' }
{ __cid: '__cid1',
method: 'insert',
options: undefined,
bindings: [ 'Transaction Doe' ],
sql: 'insert into "participants" ("name") values (?)' }
{ __cid: '__cid1',
method: 'insert',
options: undefined,
bindings: [ 1000, 'LA' ],
sql: 'insert into "towns" ("town_number", "town_title") values (?, ?)' }
[ReferenceError: p4 is not defined]
{ __cid: '__cid1', sql: 'rollback;' }
{ __cid: '__cid1',
method: 'insert',
options: undefined,
bindings: [ 3, 1, 'Transaction street name', 1 ],
sql: 'insert into "addresses" ("house_number", "participant_id", "street_name"
, "town_id") values (?, ?, ?, ?)' }
从上面的代码可以看出,发生了回滚,和上面的代码是一致的,但是回滚之后,多了一个insert。这不是应该发生的事情。
为什么 Promise.all 在代码的第一部分有效,而在第二部分似乎无效?有错误还是我没有正确理解某些东西?
感谢您的回复!
如 Bookshelf.js 开发者所述:
basically transactions don't play nicely with promise.all
据推测,Bookshelf.js 的新版本正在开发中,并承诺更好地支持交易:https://github.com/tgriesser/knex/pull/786
我已经看了好几天了,我还不能得出任何合理的解释。因此,简要介绍一下背景:我正在使用 bookshelfjs,我想使用事务来执行 3 次插入,并在保存时添加一些额外的引用。为了让事情按照我希望的方式工作,我使用了 bluebird Promise。
router.get('/transaction', function(req, res){
bookshelf.transaction(function(t){
return Promise.all([
//this block is part of transaction!
new Participant({name: 'Transaction John'}).save(null, {transacting: t}),
new Participant({name: 'Transaction Doe'}).save(null, {transacting: t}),
new Town({town_number: 1000, town_title: 'LA'}).save(null, {transacting: t})
]).spread(function(p1, p2, t1){
return Promise.all([
/*
this block, however, is not. second address save fails, because I use "p4.get('id')" which does not exists
the first address is saved, the second is not; but since I use transactions, nothing should be saved!
*/
new Address({
house_number: 3,
street_name: 'Transaction street name',
town_id: t1.get('id'),
participant_id: p1.get('id')
}).save(null, {transacting: t}),
new Address({
house_number: 3,
street_name: 'Transaction street name 2',
town_id: t1.get('id'),
participant_id: p4.get('id')
}).save(null, {transacting: t})
]);
});
}).then(function(){
res.json('success');
}).catch(function(error){
console.log('error');
res.json(error);
});
});
以上代码的查询如下:
{ __cid: '__cid1', sql: 'begin transaction;' }
{ __cid: '__cid1',
method: 'insert',
options: undefined,
bindings: [ 'Transaction John' ],
sql: 'insert into "participants" ("name") values (?)' }
{ __cid: '__cid1',
method: 'insert',
options: undefined,
bindings: [ 'Transaction Doe' ],
sql: 'insert into "participants" ("name") values (?)' }
{ __cid: '__cid1',
method: 'insert',
options: undefined,
bindings: [ 1000, 'LA' ],
sql: 'insert into "towns" ("town_number", "town_title") values (?, ?)' }
[ReferenceError: p4 is not defined]
{ __cid: '__cid1', sql: 'rollback;' }
{ __cid: '__cid1',
method: 'insert',
options: undefined,
bindings: [ 3, 1, 'Transaction street name', 1 ],
sql: 'insert into "addresses" ("house_number", "participant_id", "street_name"
, "town_id") values (?, ?, ?, ?)' }
从上面的代码可以看出,发生了回滚,和上面的代码是一致的,但是回滚之后,多了一个insert。这不是应该发生的事情。
为什么 Promise.all 在代码的第一部分有效,而在第二部分似乎无效?有错误还是我没有正确理解某些东西?
感谢您的回复!
如 Bookshelf.js 开发者所述:
basically transactions don't play nicely with promise.all
据推测,Bookshelf.js 的新版本正在开发中,并承诺更好地支持交易:https://github.com/tgriesser/knex/pull/786