如何使用 Node 从单个连接/事务进行多个数据库调用.js而且繁琐

How do you make multiple database calls from a single connection/transaction with Node.js and Tedious

本文关键字:调用 数据库 js Node 何使用 单个 连接 事务      更新时间:2023-09-26

我正在尝试将NodeJS与繁琐的(http://pekim.github.io/tedious/)sql服务器插件一起使用以进行多个数据库调用。 我的目的是:1. 打开连接2. 开始交易3. 进行多个数据库(存储过程)调用,这不会返回任何数据。4. 提交事务(或在出错时回滚)。5. 关闭连接

这是 NodeJS 的一个示例.js文件(不使用事务),我尝试进行多个数据库调用,但失败并显示错误"请求只能在 LoggedIn 状态下发出,而不是 SentClientRequest 状态"。 我尝试的任何方法都无法解决此问题。

有谁知道如何解决这个问题?

var Connection = require('tedious').Connection;
var Request = require('tedious').Request;
var config = {
    userName: 'login',
    password: 'password',
    server: '127.0.0.1',
    options: { rowCollectionOnDone: true }
};
var max = 1;
for (var i = 0; i < max; i++) {
    var connection = new Connection(config);
    function executeStatement() {
        request = new Request("select 42, 'hello world'", function (err, rowCount) {
            if (err) {
                console.log(err);
            } else {
                console.log(rowCount + ' rows');
            }
        });
        request.on('row', function (columns) {
            columns.forEach(function (column) {
                console.log(column.value);
            });
        });
        request.on('doneInProc', function (rowCount, more, rows) {
        });
        request.on('doneProc', function (rowCount, more, rows) {
            console.log('statement completed!')
            connection.execSql(request);
        });
        request.on('returnStatus', function (status) {
            console.log('statement completed!')
        });
        connection.execSql(request);
    }
    connection.on('connect', function (err) {
        // If no error, then good to go...
        executeStatement();
    });
}
console.log('Done!');

您正在尝试在未建立的连接上执行语句。在调用 executeStatement 之前缺少错误处理程序。

connection.on('connect', function (err) {
    if (err) {
        console.log(err); // replace with your code
        return;
    };
    // If no error, then good to go...
    executeStatement();
});

编辑:

如何在串行事务中执行多个语句:

var statements = ["select 1", "select 2", "select 3"];
var transaction = new sql.Transaction(connection);
transaction.begin(function(err) {
    // ... error checks
    async.mapSeries(statements, function(statement, next) {
        var request = new sql.Request(transaction);
        request.query(statement, next);
    }, function(err, results) {
        // ... error checks
        transaction.commit(function(err, recordset) {
            // ... error checks
            console.log("Transaction commited.");
        });
    });
});

您应该使用繁琐的连接池来创建包含多个连接的池。对于节点 js,npm 模块位于: https://www.npmjs.com/package/tedious-connection-pool

对于 for 循环中的每个新值,您可以获取一个新连接并在doneInProc事件上使用connection.reset。您一直在做的情况是正确执行 for 循环的第一次迭代(LoggedIn State),并且由于您继续没有关闭或释放连接,您正在使用相同的连接对象 ( SentClientRequest state )。因此,当代码达到 for 循环的第二次迭代时,同一对象处于最终状态。希望它能解决您的问题

您可以使用乏味的连接池 https://github.com/pekim/tedious-connection-pool

正如@zevsuld和@mannutech所说,乏味的连接池将启用多个连接,并防止在同时请求进入服务器时出错。

下面是一个通用示例,允许您在一个连接池中编写多个查询,并公开它们以在 API 中使用。我只是添加这个,以防其他人试图完成这种类型的实现。

const ConnectionPool = require('tedious-connection-pool');
const path = require('path');
require('dotenv').config({
  path: path.join(__dirname, '../../.env')
})
let Request = require('tedious').Request;
let poolConfig = {
  min: 10,
  max: 50,
  log: true
}
let connectionConfig  = {
  userName: process.env.user,
  password: process.env.password,
  server: process.env.server
};
//create the pool
let pool = new ConnectionPool(poolConfig, connectionConfig);
pool.on('error', function(err) {
  console.error(err);
});
// At this point in the code, we have established a connection pool.  If you run node, you'll see it log out all then connections to your database. 
// Let's add some methods which your server might use in fulfilling requests to various endpoints.  
let query1 = (cb, res, query) => {
  // acquire a connection:
  pool.acquire(function(err, connection) {
    if (err) {
      console.error(err);
      return;
    } else {
      // form your query
      let sql_query = `SELECT column1, colum2 from TABLE WHERE column1 LIKE '${query.param}%%' ORDER BY column1 ASC`
      // use the connection as usual:
      request = new Request(sql_query, (err, rowCount) => {
        if (err) {
          console.log(err);
          return;
        } else {
          // console.log('rowCount:', rowCount);
        }
        //release the connection back to the pool when finished
        connection.release();
      });
      let records = [];
      request.on("row", function(columns) {
        let rowArray = [];
        columns.forEach(function(column) {
          rowArray.push(column.value);
        });
        records.push(rowArray);
      });
      request.on("doneInProc", function() {
        cb(records, res);
      });
      // lastly exectue the request on the open connection.
      connection.execSql(request);
    }
  });
};
let query2 = (cb, res, query) => {
  // acquire a connection:
  pool.acquire(function(err, connection) {
    if (err) {
      console.error(err);
      return;
    } else {
      // form your query
      let sql_query = `SELECT column3, colum4 from TABLE2 WHERE column3 LIKE '${query.param}%%' ORDER BY column3 ASC`;
      // use the connection as usual:
      request = new Request(sql_query, (err, rowCount) => {
        if (err) {
          console.log(err);
          return;
        } else {
          // console.log('rowCount:', rowCount);
        }
        //release the connection back to the pool when finished
        connection.release();
      });
      let records = [];
      request.on("row", function(columns) {
        let rowArray = [];
        columns.forEach(function(column) {
          rowArray.push(column.value);
        });
        records.push(rowArray);
      });
      request.on("doneInProc", function() {
        cb(records, res);
      });
      // lastly exectue the request on the open connection.
      connection.execSql(request);
    }
  });
};
// Let's expose these two functions to the rest of your API:
module.exports = {
  query1,
  query2
}