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 ответа
На самом деле это не упоминается в документации модуля, но вы можете прослушивать события подключения. Поэтому, если вы хотите сохранить структуру и избежать повторений, вы можете прослушать 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()
метод.
Не совсем уверен, что шаблон, который вы используете, будет полезен с 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
});