【问题标题】:ms sql resource management using bluebird promises使用蓝鸟承诺的 ms sql 资源管理
【发布时间】:2015-04-07 01:43:02
【问题描述】:

我正在使用 mssql 模块通过节点连接到 sql server 数据库。 Bluebird 有一个类似于 c# 中的资源管理的功能。它有一个“使用”方法来避免必须使用 try/catch/finall 来处理资源。他们有 pg 和 mysql 的示例,但他们没有 mssql 的示例,它不会以与 pg 和 mysql 相同的方式创建连接。这是一个如何使用它的示例:

using(getConnection(),
  fs.readFileAsync("file.sql", "utf8"), function(connection, fileContents) {
  return connection.query(fileContents);
}).then(function() {
  console.log("query successful and connection closed");
});

但是为了能够使用这个方法,你需要创建一个描述如何关闭连接的连接方法。以下是 pg 的示例:

function getSqlConnection(connectionString) {
   var close;
   return pg.connectAsync(connectionString).spread(function(client, done) {
      close = done;
      return client;
   }).disposer(function(client) {
      if (close) close(client);
   });
}

我在使用 mssql 模块时遇到的问题是 connect 方法没有返回像 pg 甚至 mysql 模块这样的连接对象。有没有人能够用 mssql 做到这一点?

更新 1:

这是我制作交易处理器的方法:

function getTransaction(connection) {
   return new Promise(function(resolve, reject) {
       var tx = sql.Transaction(connection);
       tx.beginAsync().then(function(err) {
           if(err) {
             tx = null;
             return reject(err);
           }
           return resolve(tx);
       });
   }).disposer(function(tx, promise) {
       if(promise.isFulfilled()) {
          return tx.commitAsync();
       }
       else {
          return tx.rollbackAsync();
       }
   });
}

它似乎有效,但不确定这是否有效。现在我需要弄清楚如何在查询中捕获错误。

这就是我进行交易的方式:

using(getConnection(), function(connection) {
   return using(getTransaction(connection), function(tx) {
          return query(queryString, tx).then(function() {
               console.log('first query in transaction completed.');
               console.log('starting second query in transaction.');
               return query(anotherQueryString, tx);
          });
   });
});

如果我将单个捕获标记为外部“使用”,它会捕获整个事务中的所有错误吗?

【问题讨论】:

    标签: javascript sql-server node.js promise bluebird


    【解决方案1】:

    好问题,mssql 有非常棘手的 API(构造函数接受回调!)所以这是对文档的很好补充。

    var Promise = require("bluebird");
    var sql = Promise.promisifyAll(require("mssql"));
    global.using = Promise.using;
    
    function getConnection(config) {
        var connection;
        return new Promise(function(resolve, reject) 
            connection = new sql.Connection(config, function(err) {
                if (err) {
                    connection = null;
                    return reject(err);
                }
                resolve(connection);
            });
        }).disposer(function() {
          if (connection) connection.close();
       });
    }
    
    var config = {
        user: '...',
        password: '...',
        server: 'localhost',
        database: '...',
    };
    
    using(getConnection(config), function(connection) {
        var request = new sql.Request(connection);
        return request.queryAsync("select 1 as number").then(function(recordSet) {
            console.log("got record set", recordSet);
            return request.queryAsync("select 10 as number");
        });
    }).then(function(recordSet) {
        console.log("got record set", recordSet);
    })
    

    要使用事务,请尝试像这样实现 getTransaction:

    function getTransaction(connection) {
      var tx = new sql.Transaction(connection);
      return tx.beginAsync().thenReturn(tx).disposer(function(tx, promise) {
        return promise.isFulfilled() ? tx.commitAsync() : tx.rollbackAsync();
      });
    }
    

    并像这样使用它:

    using(getConnection(), function(connection) {
      return using(getTransaction(connection), function(tx) {
        var request = new sql.Request(tx);
        return request.queryAsync("INSERT 1...").then(function() {
          return request.queryAsync("INSERT 2...");
        }).then(function() {
          return request.queryAsync("INSERT 3...");
        });
      });
    });
    

    错误处理:

    using(getConnection(), function(connection) {
      return using(getTransaction(connection), function(tx) {
        var request = new sql.Request(tx);
        return request.queryAsync("INSERT...");
      });
    }).catch(sql.TransactionError, function(e) {
      console.log("transaction failed", e);
    }).catch(sql.ConnectionError, function(e) {
      console.log("connection failed", e);
    }).catch(sql.RequestError, function(e) {
      console.log("invalid query", e);
    });
    

    【讨论】:

    • 嗯,我试试看。只是好奇为什么你承诺所有的 mssql 但你不使用承诺?示例:您正在调用 connection.close() 而不是 connection.closeAsync()。另外,你能告诉我一种在你的例子中整合交易的方法吗?我可以看到“使用”语句在交易中真正派上用场了。
    • @u84six 因为close 是同步方法
    • 我仍然在努力让事务处理程序正常工作(提交、回滚)。当我使用嵌套的“使用”语句(第一个是 getConnection,第二个是 getTransaction)时,第一个“使用”在嵌套的语句开始之前完成(因此节点的异步性质)。你知道我可以为交易创建“使用”语句的方法吗?
    • @u84six 你能用代码提出一个单独的问题吗?你确定你只是没有忘记return
    • 我想知道你为什么要承诺 mssql 模块,而它已经支持承诺? npmjs.com/package/mssql#promises
    猜你喜欢
    • 2016-01-06
    • 1970-01-01
    • 2015-09-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-02-13
    • 2014-11-06
    • 2015-02-13
    相关资源
    最近更新 更多