简体   繁体   English

如何使用 Node.js 和 Tedious 从单个连接/事务中进行多个数据库调用

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

I am attempting to use NodeJS with the Tedious ( http://pekim.github.io/tedious/ ) sql server plugin to make multiple database calls.我正在尝试将 NodeJS 与 Tedious ( http://pekim.github.io/tedious/ ) sql server 插件一起使用来进行多个数据库调用。 My intent is to: 1. Open a connection 2. Start a transaction 3. Make multiple database (stored procedure) calls, which will not return any data.我的意图是: 1. 打开连接 2. 启动事务 3. 进行多个数据库(存储过程)调用,不会返回任何数据。 4. Commit transaction (or roll back on error). 4. 提交事务(或错误回滚)。 5. Close connection 5.关闭连接

Here is an example .js file, (without using a transaction) for NodeJS where I am attempting to make multiple database calls and it is failing with the error "Requests can only be made in the LoggedIn state, not the SentClientRequest state."这是 NodeJS 的一个示例 .js 文件(不使用事务),我在其中尝试进行多个数据库调用,但失败并显示错误“请求只能在 LoggedIn 状态下进行,不能在 SentClientRequest 状态下进行。” Nothing I try resolves this issue.我没有尝试解决这个问题。

Does anyone know how to resolve this?有谁知道如何解决这个问题?

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!');

You're trying to execute a statement on a connection that is not established.您正在尝试对未建立的连接执行语句。 You're missing an error handler before you call executeStatement .在调用executeStatement之前,您缺少错误处理程序。

connection.on('connect', function (err) {
    if (err) {
        console.log(err); // replace with your code
        return;
    };

    // If no error, then good to go...
    executeStatement();
});

Edit:编辑:

How to execute multiple statements in a transaction in serial:如何在一个事务中串行执行多条语句:

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

You should use tedious connection pools to create a pool of multiple connections.您应该使用繁琐的连接池来创建多个连接的池。 For node js, a npm module is available at : https://www.npmjs.com/package/tedious-connection-pool对于节点 js,npm 模块位于: https : //www.npmjs.com/package/tedious-connection-pool

For every new value inside for loop you can acquire a new connection and use connection.reset on doneInProc event.对于 for 循环中的每个新值,您可以获取一个新连接并在doneInProc事件上使用connection.reset The case which you have been doing is performing 1st iteration of for loop correctly( LoggedIn State ) and as you have proceeded without closing or releasing the connection you are using same connection object ( SentClientRequest state ).您一直在做的情况是正确执行 for 循环的第 1 次迭代( LoggedIn State ),并且在您没有关闭或释放连接的情况下继续使用相同的连接对象( SentClientRequest state )。 Hence the same object is at final state when the code reaches second iteration of for loop.因此,当代码到达 for 循环的第二次迭代时,同一个对象处于最终状态。 Hope it resolves your issue希望它能解决您的问题

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

As @zevsuld and @mannutech said, tedious-connection-pool will enable multiple connections, and prevent erring out when simultaneous requests come into your server.正如@zevsuld 和@mannutech 所说,tedious-connection-pool 将启用多个连接,并防止同时请求进入您的服务器时出错。

Below is a generic example that allows you to write multiple queries within one connection pool, and expose them for use in your api.下面是一个通用示例,它允许您在一个连接池中编写多个查询,并将它们公开以在您的 api 中使用。 I'm just adding this in case others come along who are trying to accomplish this type of implementation.我只是添加这个以防其他人试图完成这种类型的实现。

 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 }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM