javascript Sails.js 使用带有 promise 的事务的最佳实践(Postgres)
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/24691385/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Sails.js best practice in using transactions with promises (Postgres)
提问by Zuker
I'm using sails 0.9.16 with Postgres and my question is: what is the best way to execute transaction using current API with promises? May be there is something better than:
我在 Postgres 中使用了 Sails 0.9.16,我的问题是:使用带有承诺的当前 API 执行事务的最佳方法是什么?可能有比以下更好的东西:
Model.query('BEGIN TRANSACTION', function (err) {
if (err) {
next(err);
} else {
Model
.create(...)
.(function (value) {
return [value, RelatedModel.create(...).then(...)];
})
.fail(function (err) {
Model.query('ROLLBACK');
next(err);
})
.spread(function (...) {
Model.query('COMMIT')
next(...);
})
}
})
Thanks for help!
感谢帮助!
回答by aclave1
I'm currently using this exact workflow. For executing one query with promises do this:
我目前正在使用这个确切的工作流程。要使用承诺执行一个查询,请执行以下操作:
Model
.query(params)
.then(function(result){
//act on result
})
.catch(function(error){
//handle error
})
.done(function(){
//clean up
});
To execute multiple queries in parallel, do this:
要并行执行多个查询,请执行以下操作:
var Promise = require('q');
Promise.all([
User.findOne(),
AnotherModel.findOne(),
AnotherModel2.find()
])
.spread(function(user,anotherModel,anotherModel2){
//use the results
})
.catch(function(){
//handle errors
})
.done(function(){
//clean up
});
If you're trying to avoid nesting in your code:
如果您试图避免在代码中嵌套:
Model
.query(params)
.then(function(result){//after query #1
//since you're returning a promise here, you can use .then after this
return Model.query();
})
.then(function(results){//after query#2
if(!results){
throw new Error("No results found in query #2");
}else{
return Model.differentQuery(results);
}
})
.then(function(results){
//do something with the results
})
.catch(function(err){
console.log(err);
})
.done(function(){
//cleanup
});
Note:currently, waterline uses Q for promises. There is a pull request to switch waterline from Q to bluebird here: waterline/bluebird
注意:目前, waterline 使用 Q 作为 promises。这里有一个将水线从 Q 切换到 bluebird 的拉取请求:waterline/bluebird
When I answered this question, I'd yet to take the database class in college, so I didn't know what a transaction was. I did some digging, and bluebird allows you to do transactions with promises. The only problem is, this isn't exactly built into sails since it's some what of a special use case. Here's the code bluebird provides for this situation.
当我回答这个问题时,我还没有在大学上过数据库课程,所以我不知道什么是事务。我做了一些挖掘,bluebird 允许您使用 promise 进行交易。唯一的问题是,这并没有完全内置到帆中,因为它是一个特殊的用例。这是 bluebird 为这种情况提供的代码。
var pg = require('pg');
var Promise = require('bluebird');
Promise.promisifyAll(pg);
function getTransaction(connectionString) {
var close;
return pg.connectAsync(connectionString).spread(function(client, done) {
close = done;
return client.queryAsync('BEGIN').then(function () {
return client;
});
}).disposer(function(client, promise) {
if (promise.isFulfilled()) {
return client.queryAsync('COMMIT').then(closeClient);
} else {
return client.queryAsync('ROLLBACK').then(closeClient);
}
function closeClient() {
if (close) close(client);
}
});
}
exports.getTransaction = getTransaction;
回答by vitaly-t
The best way to deal with transactions is when they are wrapped properly by a promise library, because transaction logic maps perfectly into the promise event chain, one doesn't have to worry about when to do COMMIT
or ROLLBACK
, as it happens automatically.
处理事务的最好方法是当它们被一个 Promise 库正确包装时,因为事务逻辑完美地映射到 Promise 事件链中,人们不必担心何时执行COMMIT
或ROLLBACK
,因为它会自动发生。
Here's a complete example of how it works with pg-promiselibrary:
这是一个完整的示例,说明它如何与pg-promise库配合使用:
var pgp = require('pg-promise')(/*options*/);
var cn = "postgres://username:password@host:port/database";
var db = pgp(cn); // database instance;
db.tx(t => {
// BEGIN has been executed
return t.batch([
t.one("insert into users(name) values() returning id", 'John'),
t.one("insert into users(name) values() returning id", 'Mike')
]);
})
.then(data => {
// COMMIT has been executed
console.log(data[0].id); // print id assigned to John;
console.log(data[1].id); // print id assigned to Mike;
})
.catch(error => {
// ROLLBACK has been executed
console.log(error); // print why failed;
});