Я пытаюсь понять, как структурировать свое приложение для наиболее эффективного использования MySQL. Я использую модуль node-mysql. Другие потоки здесь предложили использовать пул соединений, поэтому я установил небольшой модуль mysql.js
var mysql = require('mysql');
var pool = mysql.createPool({
host : 'localhost',
user : 'root',
password : 'root',
database : 'guess'
});
exports.pool = pool;
Теперь, когда я хочу запросить mysql, мне нужен этот модуль, а затем запрашиваю базу данных
var mysql = require('../db/mysql').pool;
var test = function(req, res) {
mysql.getConnection(function(err, conn){
conn.query("select * from users", function(err, rows) {
res.json(rows);
})
})
}
Это хороший подход? Я не смог найти слишком много примеров использования соединений mysql, кроме очень простого, где все делается в основном сценарии app.js, поэтому я действительно не знаю, каковы соглашения / лучшие практики.
Должен ли я всегда использовать connection.end () после каждого запроса? Что, если я где-нибудь об этом забуду?
Как переписать часть экспорта моего модуля mysql, чтобы возвращать только соединение, чтобы мне не приходилось каждый раз писать getConnection ()?
connection.query
моем коде есть все места» - вероятно, пришло время провести рефакторинг. Построить класс абстракции базы данных , которая предлагаетselect
,insert
,update
и т.д. - и только использоватьconnection
(илиpool
) в пределах этого одного класса дб ...Ответы:
Это хороший подход.
Если вы просто хотите установить соединение, добавьте следующий код в свой модуль, в котором находится пул:
var getConnection = function(callback) { pool.getConnection(function(err, connection) { callback(err, connection); }); }; module.exports = getConnection;
Вам все равно придется каждый раз писать getConnection. Но вы можете сохранить соединение в модуле при первом подключении.
Не забудьте разорвать соединение, когда закончите его использовать:
connection.release();
источник
connection.release();
сейчас, для бассейнов.pool.query()
напрямую. Это ярлык для потока кодаpool.getConnection()
->connection.query()
->connection.release()
.Вам следует избегать использования,
pool.getConnection()
если можете. Если вы звонитеpool.getConnection()
, вы должны позвонить,connection.release()
когда закончите использовать соединение. В противном случае ваше приложение застрянет в ожидании возврата соединений в пул, как только вы достигнете предела количества подключений.Для простых запросов вы можете использовать
pool.query()
. Это сокращение будет автоматически вызыватьconnection.release()
вас - даже в случае ошибки.function doSomething(cb) { pool.query('SELECT 2*2 "value"', (ex, rows) => { if (ex) { cb(ex); } else { cb(null, rows[0].value); } }); }
Однако в некоторых случаях необходимо использовать
pool.getConnection()
. Эти случаи включают:Если вы должны использовать
pool.getConnection()
, убедитесь, что вы вызываетеconnection.release()
с использованием шаблона, подобного приведенному ниже:function doSomething(cb) { pool.getConnection((ex, connection) => { if (ex) { cb(ex); } else { // Ensure that any call to cb releases the connection // by wrapping it. cb = (cb => { return function () { connection.release(); cb.apply(this, arguments); }; })(cb); connection.beginTransaction(ex => { if (ex) { cb(ex); } else { connection.query('INSERT INTO table1 ("value") VALUES (\'my value\');', ex => { if (ex) { cb(ex); } else { connection.query('INSERT INTO table2 ("value") VALUES (\'my other value\')', ex => { if (ex) { cb(ex); } else { connection.commit(ex => { cb(ex); }); } }); } }); } }); } }); }
Лично я предпочитаю использовать
Promise
s иuseAsync()
узор. Этот шаблон в сочетании сasync
/await
делает намного сложнее случайно забытьrelease()
о соединении, потому что он превращает вашу лексическую область видимости в автоматический вызов.release()
:async function usePooledConnectionAsync(actionAsync) { const connection = await new Promise((resolve, reject) => { pool.getConnection((ex, connection) => { if (ex) { reject(ex); } else { resolve(connection); } }); }); try { return await actionAsync(connection); } finally { connection.release(); } } async function doSomethingElse() { // Usage example: const result = await usePooledConnectionAsync(async connection => { const rows = await new Promise((resolve, reject) => { connection.query('SELECT 2*4 "value"', (ex, rows) => { if (ex) { reject(ex); } else { resolve(rows); } }); }); return rows[0].value; }); console.log(`result=${result}`); }
источник
usePooledConnectionAsync()
до завершения первой. Обратите внимание, что при использовании пула вы должны быть уверены, что избегаетеawait
событий, отличных от завершения запроса в функции, которую вы передаете как - вactionAsync
противном случае вы можете создать тупик (например, получить последнее соединение из пула, а затем вызвать другая функция, которая пытается загрузить данные, используя пул, который будет вечно ждать, чтобы попытаться получить собственное соединение из пустого пула).await
одно, прежде чем просить о следующем. Сейчас я не проводил никакого анализа, но,await
когда они действительно нужны для объединения результатов, - способ сделать это. (хотя я боюсь, что это приведет к ложным срабатываниям необработанных событий отклонения обещаний, которые могут привести к сбою node.js в будущем--unhandled-rejections=strict
).Вы найдете эту обертку полезной :)
var pool = mysql.createPool(config.db); exports.connection = { query: function () { var queryArgs = Array.prototype.slice.call(arguments), events = [], eventNameIndex = {}; pool.getConnection(function (err, conn) { if (err) { if (eventNameIndex.error) { eventNameIndex.error(); } } if (conn) { var q = conn.query.apply(conn, queryArgs); q.on('end', function () { conn.release(); }); events.forEach(function (args) { q.on.apply(q, args); }); } }); return { on: function (eventName, callback) { events.push(Array.prototype.slice.call(arguments)); eventNameIndex[eventName] = callback; return this; } }; } };
Требуйте это, используйте это так:
db.connection.query("SELECT * FROM `table` WHERE `id` = ? ", row_id) .on('result', function (row) { setData(row); }) .on('error', function (err) { callback({error: true, err: err}); });
источник
Я использую это соединение базового класса с mysql:
"base.js"
var mysql = require("mysql"); var pool = mysql.createPool({ connectionLimit : 10, host: Config.appSettings().database.host, user: Config.appSettings().database.username, password: Config.appSettings().database.password, database: Config.appSettings().database.database }); var DB = (function () { function _query(query, params, callback) { pool.getConnection(function (err, connection) { if (err) { connection.release(); callback(null, err); throw err; } connection.query(query, params, function (err, rows) { connection.release(); if (!err) { callback(rows); } else { callback(null, err); } }); connection.on('error', function (err) { connection.release(); callback(null, err); throw err; }); }); }; return { query: _query }; })(); module.exports = DB;
Просто используйте это так:
var DB = require('../dal/base.js'); DB.query("select * from tasks", null, function (data, error) { callback(data, error); });
источник
err
верен? не должен он по- прежнему называтьcallback
сnull
параметром , чтобы указать , есть какая - то ошибка в запросе?else
условие:if (!err) { callback(rows, err); } else { callback(null, err); }
иначе ваше приложение может зависнуть. Потомуconnection.on('error', callback2)
что не позаботится обо всех «ошибках». Благодаря!Когда вы закончите с подключением, просто позвоните,
connection.release()
и соединение вернется в пул, готовый к повторному использованию кем-то другим.var mysql = require('mysql'); var pool = mysql.createPool(...); pool.getConnection(function(err, connection) { // Use the connection connection.query('SELECT something FROM sometable', function (error, results, fields) { // And done with the connection. connection.release(); // Handle error after the release. if (error) throw error; // Don't use the connection here, it has been returned to the pool. }); });
Если вы хотите закрыть соединение и удалить его из пула, используйте
connection.destroy()
вместо этого. Пул создаст новое соединение, когда оно понадобится в следующий раз.Источник : https://github.com/mysqljs/mysql
источник
Используя стандартный mysql.createPool (), соединения лениво создаются пулом. Если вы сконфигурируете пул так, чтобы разрешить до 100 подключений, но использовать только 5 одновременно, будет выполнено только 5 подключений. Однако, если вы настроите его на 500 подключений и используете все 500, они останутся открытыми в течение всего процесса, даже если они простаивают!
Это означает, что если ваш MySQL Server max_connections равен 510, ваша система будет иметь только 10 подключений mySQL, пока ваш MySQL Server не закроет их (в зависимости от того, что вы установили для вашего wait_timeout) или ваше приложение не закроется! Единственный способ освободить их - вручную закрыть соединения через экземпляр пула или закрыть пул.
Модуль mysql-connection-pool-manager был создан для решения этой проблемы и автоматического масштабирования количества подключений в зависимости от нагрузки. Неактивные соединения закрываются, а пулы незанятых соединений в конечном итоге закрываются, если не было никакой активности.
// Load modules const PoolManager = require('mysql-connection-pool-manager'); // Options const options = { ...example settings } // Initialising the instance const mySQL = PoolManager(options); // Accessing mySQL directly var connection = mySQL.raw.createConnection({ host : 'localhost', user : 'me', password : 'secret', database : 'my_db' }); // Initialising connection connection.connect(); // Performing query connection.query('SELECT 1 + 1 AS solution', function (error, results, fields) { if (error) throw error; console.log('The solution is: ', results[0].solution); }); // Ending connection connection.end();
Ссылка: https://www.npmjs.com/package/mysql-connection-pool-manager
источник
я всегда использую connection.relase (); после pool.getconnetion вроде
pool.getConnection(function (err, connection) { connection.release(); if (!err) { console.log('*** Mysql Connection established with ', config.database, ' and connected as id ' + connection.threadId); //CHECKING USERNAME EXISTENCE email = receivedValues.email connection.query('SELECT * FROM users WHERE email = ?', [email], function (err, rows) { if (!err) { if (rows.length == 1) { if (bcrypt.compareSync(req.body.password, rows[0].password)) { var alldata = rows; var userid = rows[0].id; var tokendata = (receivedValues, userid); var token = jwt.sign(receivedValues, config.secret, { expiresIn: 1440 * 60 * 30 // expires in 1440 minutes }); console.log("*** Authorised User"); res.json({ "code": 200, "status": "Success", "token": token, "userData": alldata, "message": "Authorised User!" }); logger.info('url=', URL.url, 'Responce=', 'User Signin, username', req.body.email, 'User Id=', rows[0].id); return; } else { console.log("*** Redirecting: Unauthorised User"); res.json({"code": 200, "status": "Fail", "message": "Unauthorised User!"}); logger.error('*** Redirecting: Unauthorised User'); return; } } else { console.error("*** Redirecting: No User found with provided name"); res.json({ "code": 200, "status": "Error", "message": "No User found with provided name" }); logger.error('url=', URL.url, 'No User found with provided name'); return; } } else { console.log("*** Redirecting: Error for selecting user"); res.json({"code": 200, "status": "Error", "message": "Error for selecting user"}); logger.error('url=', URL.url, 'Error for selecting user', req.body.email); return; } }); connection.on('error', function (err) { console.log('*** Redirecting: Error Creating User...'); res.json({"code": 200, "status": "Error", "message": "Error Checking Username Duplicate"}); return; }); } else { Errors.Connection_Error(res); } });
источник