【问题标题】:node-mssql multiple prepared statements with single connectionnode-mssql 带有单个连接的多个准备好的语句
【发布时间】:2017-01-16 23:51:27
【问题描述】:

我正用头撞这个图书馆。我尝试设置一个单例中间类来启动连接,然后通过静态方法共享该连接。我的问题是我很难设置一些东西,以便在运行查询时连接已经打开,但不必再次重新打开它。由于连接的打开当然是异步的,所以我不能将所有内容都放在打开回调中,因为这完全发生在另一个时间的其他地方......我唯一能做的就是分享mssql.Connection,即@ 987654322@。这就是为什么我在Database.connect()中不做connection.connect()

在知道连接已打开的情况下,如何打开连接并继续准备语句和运行查询?

我的问题是每当我的代码从第二次开始到达connection.connect(),它就会遇到错误EALREADYCONNECTING,因为连接已经被打开了。

我想过做某种 Promise 查询池,一旦连接本身通过 Promise 解决,就可以解决,但现在我的大脑非常混乱!

let mssql = require('mssql');
let fs = require('fs');

class Database
{

  static connect(username, password, server, database)
  {
    if (Database.connection !== null) {
      return Database.connection;
    }

    let storedUsername = null;
    let storedPassword = null;
    let storedServer = null;
    let storedDatabase = null;

    try {
      fs.accessSync(__dirname + '/../../config.json');

      let data = fs.readFileSync(__dirname + '/../../config.json')
      data = JSON.parse(data);
      storedUsername = data.sql.username;
      storedPassword = data.sql.password;
      storedServer = data.sql.server;
      storedDatabase = data.sql.database;

    } catch (e) {
      // Do nothing
    }

    var config = {
      user: username || storedUsername || '',
      password: password || storedPassword || '',
      server: server || storedServer || 'localhost',
      database: database || storedDatabase || '',
    }

    Database.connection = new mssql.Connection(config);

    return Database.connection;
  }

  static getConnection()
  {
    if (Database.connection === null) {
      try {
        Database.connect();
      } catch (e) {
        throw new Error('Database.getConnection: Database not connected.');
      }
    }

    return Database.connection;
  }

  static getInstance()
  {
    return mssql;
  }

  static query(query, fields)
  {
    if (typeof query !== 'string' || typeof fields !== 'object') {
      throw new Error("Invalid parameters");
    }

    let db = Database.getInstance();
    let connection = Database.getConnection();
    let ps = new db.PreparedStatement(connection);
    let values = {};

    fields.forEach(function(current, index) {
      ps.input(current.name, current.type);
      values[current.name] = current.value;
    });

    connection.connect(function(err) {
      if (err) {
        throw err;
      }

      ps.prepare(query, function(err) {
        if (err) {
          throw new Error(err);
        }

        ps.execute(values, function(err, recordset, affected) {
          if (err) {
            ps.unprepare(function(err) {
              if (err) {
                throw new Error(err);
              }
            });
            throw new Error(err);
          }

          ps.unprepare(function(err) {
            if (err) {
              throw new Error(err);
            }
          });
        });
      });
    });
  }
}

Database.connection = null;

module.exports = Database;

【问题讨论】:

  • 最简单的方法是在 Database.connect 中强制连接。在那里执行connection.connect,然后执行一段SQL,返回一个可以使用或丢弃的值。一个简单的SELECT @@VERSION 应该足以让代码执行在那里直到连接打开。当然,您也可以在 getConnection() 调用中使用相同的机制。基本上,如果您不希望出现该错误,请通过添加一个要求在代码继续之前打开连接的任务来强制代码等待连接完成打开。
  • 感谢您的意见!好吧,问题的关键是在建立连接之前我不知道如何保持执行。 ???有时我想要的只是"async": false ????

标签: sql-server node.js node-mssql


【解决方案1】:

不太确定您所遵循的模式是否对 node.js 有用,它对于非事件驱动编程非常有用,但要使其与 node.js 一起使用,您需要按照 cmets 中的建议进行循环。这只是违背了目的。

第二点是您实际上是在为 mssql 类创建一个包装器,这增加了另一层复杂性,可能会引入错误并使维护变得更加困难。下一个编写此代码的人会知道 mssql,但不会知道您正在创建的类以及您必须实施以使其工作的变通方法。

使用一个连接的最佳方法是将所有查询放在连接时回调中

try {
  fs.accessSync(__dirname + '/../../config.json');

  let data = fs.readFileSync(__dirname + '/../../config.json')
  data = JSON.parse(data);
  storedUsername = data.sql.username;
  storedPassword = data.sql.password;
  storedServer = data.sql.server;
  storedDatabase = data.sql.database;

} catch (e) {
  // Actually you must do something here. If nothing else
  // at least log it so that later on you are not left wondering 
  // why nothing seems to work.
}

var config = {
  user: username || storedUsername || '',
  password: password || storedPassword || '',
  server: server || storedServer || 'localhost',
  database: database || storedDatabase || '',
}

Database.connection = new mssql.Connection(config);
connection.connect(function(err) {
    // do everything here    
});

【讨论】:

  • 非常感谢!很明显我对节点和事件驱动编程有点陌生吗? ? 在我看来,使用类以结构化方式组织代码的价值胜过您可以在要使用它的地方设置数据库连接的想法!
  • 好吧,在做其他事情时(?)我意识到:事件!所以我发现我可以在query() 里面做Database.connection.on('connect', function(){}) 来做我想做的事!
【解决方案2】:

module documentation 中并没有真正提到,但是可以监听连接事件。因此,如果您想保持结构井井有条并避免重复,您可以在Connection 上收听connect 事件。这对我来说似乎是完美的答案。

let mssql = require('mssql');
let fs = require('fs');

class Database
{

  static connect(username, password, server, database)
  {
    if (Database.connection !== null) {
      return Database.connection;
    }

    let storedUsername = null;
    let storedPassword = null;
    let storedServer = null;
    let storedDatabase = null;

    try {
      fs.accessSync(__dirname + '/../../config.js');

      let config = require(__dirname + '/../../config')

      storedUsername = config.sql.username;
      storedPassword = config.sql.password;
      storedServer = config.sql.server;
      storedDatabase = config.sql.database;

    } catch (err) {
      console.log(err);
    }

    let configuration = {
      user: username || storedUsername || '',
      password: password || storedPassword || '',
      server: server || storedServer || 'localhost',
      database: database || storedDatabase || '',
    }

    Database.connection = new mssql.Connection(configuration);

    Database.connection.connect();
  }

  static disconnect()
  {
    Database.connection.close();
  }

  static getConnection()
  {
    if (Database.connection === null) {
      try {
        Database.connect();
      } catch (e) {
        throw new Error('Database.getConnection: Database not connected.');
      }
    }

    return Database.connection;
  }

  static getInstance()
  {
    return mssql;
  }

  static query(query, fields)
  {
    if (typeof query !== 'string' || typeof fields !== 'object') {
      throw new Error("Invalid parameters");
    }

    let db = Database.getInstance();
    let connection = Database.getConnection();
    let ps = new db.PreparedStatement(connection);
    let values = {};

    fields.forEach(function(current, index) {
      ps.input(current.name, current.type);
      values[current.name] = current.value;
    });

    connection.on('connect', function(err) {
      if (err) {
        throw err;
      }

      ps.prepare(query, function(err) {
        if (err) {
          throw new Error(err);
        }

        ps.execute(values, function(err, recordset, affected) {
          if (err) {
            ps.unprepare(function(err) {
              if (err) {
                throw new Error(err);
              }
            });
            throw new Error(err);
          }

          ps.unprepare(function(err) {
            if (err) {
              throw new Error(err);
            }
          });
        });
      });
    });
  }
}

Database.connection = null;

module.exports = Database;

现在也许我应该在 query() 方法中 Promise-fy 那些回调。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-05-08
    • 2013-10-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多