node-mssql具有单个连接的多个预准备语句

时间:2017-01-16 23:51:28

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

我正在撞击这个图书馆。我试图设置一个单例中间类,它将启动连接,然后通过静态方法共享该连接。我的问题是我在设置事物时遇到困难,以至于在运行查询时连接已经打开,但无需再次重新打开。由于连接的打开当然是异步的,我不能只把所有内容都放在开始回调中,因为这在其他时间完全发生在其他地方......我唯一能做的就是分享mssql.Connection,是"connecting": true。这就是我不在connection.connect()

Database.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;

2 个答案:

答案 0 :(得分:1)

不完全确定你所遵循的模式是否对node.js有用,它对于非事件驱动的编程非常有用,但是要使它与node.js一起使用,你需要按照注释中的建议进行循环。这只是打败了目的。

第二点是你实际上是在为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    
});

答案 1 :(得分:0)

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()方法中承诺那些回调。