Node.js mssql 与 SQL 服务器的多个并发连接相互干扰

2024-03-05

我在用mssql在我的 Node.js Express 应用程序中,跨许多不同的 SQL 服务器连接到许多不同的数据库。

我构建了以下示例来演示代码的一般结构:

app.get('/api/example'), async (request, response) => {

    // FYI I may be using await incorrect here since I'm new to it, just using it here for code simplicity
    let results1 = await GetDataFromSqlServerA()
    let results2 = await GetDataFromSqlServerB()

    response.status(200).send([results1, results2])
});

function GetDataFromSqlServerA() {
    return new Promise(function(resolve, reject)    {

        let sql = require("mssql")

        let sqlConnectionDetails = {
            user: 'test',
            password: 'foobar',
            server: 'SQLServerA', 
            database: 'DatabaseA'
        }

        sql.connect(sqlConnectionDetails, function (error)    {

            let sqlRequest = new sql.Request()
            let queryText = 'SELECT * FROM TableA'

            sqlRequest.query(queryText, function (error, results) {
                sql.close()
                resolve(results)
            })
        })
    })
}

function GetDataFromSqlServerB() {
        return new Promise(function(resolve, reject)    {

        let sql = require("mssql")

        let sqlConnectionDetails = {
            user: 'test',
            password: 'foobar',
            server: 'SQLServerB', 
            database: 'DatabaseB'
        }

        sql.connect(sqlConnectionDetails, function (error)    {

            let sqlRequest = new sql.Request()
            let queryText = 'SELECT * FROM TableB'

            sqlRequest.query(queryText, function (error, results) {
                sql.close()
                resolve(results)
            })
        })
    })
}

我发出一个请求,该请求异步地从两个单独的 SQL 服务器位置查找数据。第一个 SQL 调用执行正常,但第二个调用失败Invalid object 'Table2'。它找不到该表,因为第二个调用出于某种原因获取了第一个调用的连接详细信息。它指向错误的 SQL 服务器和数据库!

我本以为这是不可能的,因为这些函数都在它们自己的范围内。第一个 SQL 调用应该对第二个 SQL 调用一无所知,反之亦然——或者至少我是这么认为的。

我也尝试过定义一个实例sql在全球范围内,但同样的问题也发生了。

我可以使用单个函数与服务器 A 建立 SQL 连接,向服务器 A 发出请求,与服务器 A 断开连接,与服务器 B 建立 SQL 连接,最后向服务器 B 发出请求。但是,当异步性发挥作用时并且 SQL 是由并发请求触发的,我遇到了问题。

希望我只是愚蠢,因为我是异步代码的新手,请赐教!谢谢你!


我想我会更新这个以防其他人遇到类似的麻烦。 @AlwaysLearning 为我提供了 mssql npm 文档的一部分的链接,该文档解释了连接池以及在需要访问多个数据库时执行此操作。我建议通读它 https://www.npmjs.com/package/mssql#advanced-pool-management.

原来mssql的.connect()函数是全局的。如果调用 .connect() 函数时全局池已经连接,它将解析为已连接的池。这给我带来了麻烦,因为当快速连续发送两个请求时,我的应用程序中会发生以下情况:

  1. 请求 1 将连接到数据库 A
  2. 请求2将尝试连接到数据库B
  3. 由于数据库 A 已在全局池中连接,因此请求 2 获取数据库 A 连接
  4. 请求2的SQL查询失败,因为它对于数据库A无效

为了解决这个问题,您需要开发一些连接池管理代码。通过这种方式,您可以确保每个必要的数据库连接都有单独的连接池。此外,这是一种加快查询速度的简单方法,因为您不必每次发出请求时都重新连接到数据库。

npm 文档提供了几个示例帮助程序文件,但我发现它们对我来说并不理想,而且我无法编译我的环境中的所有代码。我将代码定制如下:

mssql-connection-pooling.js:

const { ConnectionPool } = require('mssql')
const pools = {}
 
// create a new connection pool
function CreatePool(config) {
    let key = JSON.stringify(config)

    if (GetPool(key))
        throw new Error('Pool already exists')

    pools[key] = (new ConnectionPool(config)).connect()
    return pools[key]
}

// get a connection pool from all pools
function GetPool(name) {
  if (pools[name])
    return pools[name]
  else
    return null
}

// if pool already exists, return it, otherwise create it
function GetCreateIfNotExistPool(config)  {
    let key = JSON.stringify(config)

    let pool = GetPool(key)
    if(pool)
        return pool
    else
        return CreatePool(config)
}

// close a single pool
function ClosePool(config) {
    let key = JSON.stringify(config)

    if (pools[key]) {
        const pool = pools[key];
        delete pools[key];
        pool.close()
        return true
    }
    return false
}

// close all the pools
function CloseAllPools() {
    pools.forEach((pool) => {
        pool.close()
    })
    pools = {}
    return true
}
 
module.exports = {
  ClosePool,
  CloseAllPools,
  CreatePool,
  GetPool,
  GetCreateIfNotExistPool
}

我创建了 GetCreateIfNotExistPool() 函数,您可以通过该函数提供数据库连接配置对象。该函数检查池中是否存储了给定连接配置的打开连接。如果有,它只是返回连接池。如果没有,它会创建它然后返回它。

使用示例:

const sql = require("mssql");
let mssql = require('./mssql-pool-management.js')

let exampleDBConfigA = {
    user: 'test',
    password: 'password,
    server: 'SqlServerA', 
    database: 'DatabaseA'
};
let exampleDBConfigB = {
    user: 'test',
    password: 'password,
    server: 'SqlServerB', 
    database: 'DatabaseB'
};

...

// Request 1
try {
    let sqlPool = await mssql.GetCreateIfNotExistPool(exampleDBConfigA)
    let request = new sql.Request(sqlPool)

    // query code
}
catch(error) {
    //error handling
}

...

// Request 2
try {
    let sqlPool = await mssql.GetCreateIfNotExistPool(exampleDBConfigB)
    let request = new sql.Request(sqlPool)

    // query code
}
catch(error) {
    //error handling
}

在此示例中,请求 1 和 2 可以同时调用,而不会干扰它们的连接!

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Node.js mssql 与 SQL 服务器的多个并发连接相互干扰 的相关文章

随机推荐