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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-28 03:15:03  来源:igfitidea点击:

Sails.js best practice in using transactions with promises (Postgres)

javascriptnode.jssails.jswaterline

提问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 COMMITor ROLLBACK, as it happens automatically.

处理事务的最好方法是当它们被一个 Promise 库正确包装时,因为事务逻辑完美地映射到 Promise 事件链中,人们不必担心何时执行COMMITROLLBACK,因为它会自动发生。

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;
    });