我得到了正确的输出,实际上,这两个操作被视为单个事务单元;如果一个失败,那么两个都失败了。
在此代码示例中:我正在进行
的事务(1)插入 (2)更新
我接近它的方法是将我的数据库操作嵌套在.then中。 我的问题是,这个代码是偶然的吗?我是承诺和knex的新手。
knex.transaction(function(t) {
knex('foo')
.transacting(t)
.insert({id:"asdfk", username:"barry", email:"barry@bar.com"})
.then(function() {
knex('foo')
.where('username','=','bob')
.update({email:"bob@foo.com"})
.then(t.commit, t.rollback)
})
})
.then(function() {
// it worked
},
function() {
// it failed
});
这很有效,但我觉得我还在做错事。寻找意见。
答案 0 :(得分:26)
您需要从内部查询返回一个promise,以便将外链与之链接。
你也可以吞下任何错误,因为你不会重新抛出它们 - 因为这样可以更好地使用.catch()
因为它会使正在发生的事情变得更加清晰 - 这就是正常的try-catch
陈述。
knex.transaction(function(t) {
return knex('foo')
.transacting(t)
.insert({id:"asdfk", username:"barry", email:"barry@bar.com"})
.then(function() {
return knex('foo')
.where('username','=','bob')
.update({email:"bob@foo.com"});
})
.then(t.commit)
.catch(function(e) {
t.rollback();
throw e;
})
})
.then(function() {
// it worked
})
.catch(function(e) {
// it failed
});
为了更好地理解它,这里是正在模拟的同步版本":
try {
var t = knex.transaction();
try {
knex("foo")
.transacting(t)
.insert({id:"asdfk", username:"barry", email:"barry@bar.com"});
knex("foo")
.where('username','=','bob')
.update({email:"bob@foo.com"});
t.commit();
}
catch (e) {
t.rollback();
// As you can see, if you don't rethrow here
// the outer catch is never triggered
throw e;
}
// It worked
}
catch (e) {
//It failed
}
答案 1 :(得分:1)
我在这里尝试接受的答案。它向我抛出了一些错误,例如“事务查询已经完成”和“数据库锁定”。答案很旧,因此可能正在使用以前的版本。我正在使用 Sqlite3.34.1
和 knex0.95.4
。该代码对我进行了一些调整。添加在此线程中,它可以帮助某人。
async function process() {
await knex.transaction(function(t) {
return knex('foo')
.transacting(t)
.insert({id:"asdfkg", username:"bob", email:"bob@bar.com"})
.then(function() {
return t('foo').insert({id:"abcd", username:"john", email:"john@bar.com"})
})
.then(function() {
return t('foo')
.where('username','=','bob')
.update({email:"bob@foo.com"});
})
})
.then(function() {
console.log("it worked")
})
.catch(function(e) {
console.log(e)
console.log("It failed")
});
knex.destroy()
}
我认为,回滚和提交是由它自己处理的,我们不必明确指定。