Ich versuche herauszufinden, wie ich meine Anwendung so strukturieren kann, dass MySQL auf effizienteste Weise verwendet wird. Ich verwende das Node-MySQL-Modul. Andere Threads hier schlugen vor, Verbindungspooling zu verwenden, also richtete ich ein kleines Modul mysql.js ein
var mysql = require('mysql');
var pool = mysql.createPool({
host : 'localhost',
user : 'root',
password : 'root',
database : 'guess'
});
exports.pool = pool;
Wann immer ich MySQL abfragen möchte, benötige ich dieses Modul und frage dann die Datenbank ab
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);
})
})
}
Ist das ein guter Ansatz? Ich konnte nicht wirklich viele Beispiele für die Verwendung von MySQL-Verbindungen finden, außer einer sehr einfachen, bei der alles im Skript main app.js ausgeführt wird, sodass ich die Konventionen / Best Practices nicht wirklich kenne.
Sollte ich nach jeder Abfrage immer connection.end () verwenden? Was ist, wenn ich es irgendwo vergesse?
Wie schreibe ich den Exportteil meines MySQL-Moduls neu, um nur eine Verbindung zurückzugeben, damit ich nicht jedes Mal getConnection () schreiben muss?
connection.query
überall in meinem Code" - es ist wahrscheinlich Zeit für eine Umgestaltung. Erstellen Sie eine Datenbank - Abstraktions Klasse, die Angeboteselect
,insert
,update
, usw. - und nur verwendenconnection
(oderpool
innerhalb dieser einzigen db - Klasse) ...Antworten:
Es ist ein guter Ansatz.
Wenn Sie nur eine Verbindung herstellen möchten, fügen Sie Ihrem Modul, in dem sich der Pool befindet, den folgenden Code hinzu:
var getConnection = function(callback) { pool.getConnection(function(err, connection) { callback(err, connection); }); }; module.exports = getConnection;
Sie müssen immer noch jedes Mal getConnection schreiben. Sie können die Verbindung jedoch beim ersten Erhalt im Modul speichern.
Vergessen Sie nicht, die Verbindung zu beenden, wenn Sie fertig sind:
connection.release();
quelle
connection.release();
jetzt für Pools.pool.query()
direkt verwenden. Dies ist eine Verknüpfung für den Codeflusspool.getConnection()
->connection.query()
->connection.release()
.Sie sollten die Verwendung vermeiden,
pool.getConnection()
wenn Sie können. Wenn Sie anrufenpool.getConnection()
, Sie müssen rufen Sie,connection.release()
wenn Sie die Verbindung nicht mehr verwenden. Andernfalls bleibt Ihre Anwendung hängen und wartet ewig darauf, dass Verbindungen zum Pool zurückgegeben werden, sobald Sie das Verbindungslimit erreicht haben.Für einfache Abfragen können Sie verwenden
pool.query()
. Diese Abkürzung ruft automatischconnection.release()
nach Ihnen - auch unter Fehlerbedingungen.function doSomething(cb) { pool.query('SELECT 2*2 "value"', (ex, rows) => { if (ex) { cb(ex); } else { cb(null, rows[0].value); } }); }
In einigen Fällen müssen Sie jedoch verwenden
pool.getConnection()
. Diese Fälle umfassen:Wenn Sie verwenden müssen
pool.getConnection()
, stellen Sie sicher, dass Sieconnection.release()
mit einem ähnlichen Muster wie unten anrufen :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); }); } }); } }); } }); } }); }
Ich persönlich bevorzuge
Promise
s und dasuseAsync()
Muster. Dieses Muster in Kombination mitasync
/await
macht es viel schwieriger,release()
die Verbindung versehentlich zu vergessen, da es Ihr lexikalisches Scoping in einen automatischen Aufruf verwandelt an.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}`); }
quelle
usePooledConnectionAsync()
vor Abschluss des ersten Vorgangs mehrmals anzurufen. Beachten Sie, dass Sie beim Pooling sicherstellen möchten, dass Sieawait
andere Ereignisse als den Abschluss der Abfrage innerhalb der FunktionactionAsync
vermeiden, die Sie als übergeben. Andernfalls kann es zu einem Deadlock kommen (z. B. die letzte Verbindung aus einem Pool abrufen und dann aufrufen) eine andere Funktion, die versucht, Daten über den Pool zu laden, die ewig warten wird, um zu versuchen, eine eigene Verbindung aus dem Pool zu erhalten, wenn sie leer ist).await
eine zu sein, bevor man nach der nächsten fragt. Ich habe noch keine Analyse durchgeführt, aber so wie ich Dinge verfasst habe (neue Versprechen zurückgeben), denke ich, dass es immer noch parallel läuft ...await
ausführen, wenn Sie sie tatsächlich benötigen, um die Ergebnisse zusammenzustellen (obwohl ich Angst habe, dass dies zu falsch positiven, nicht behandelten Versprechungsverweigerungsereignissen führen würde, mit denen node.js in Zukunft abstürzen könnte--unhandled-rejections=strict
).Sie finden diesen Wrapper nützlich :)
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; } }; } };
Benötigen Sie es, verwenden Sie es wie folgt:
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}); });
quelle
Ich verwende diese Basisklassenverbindung mit 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;
Verwenden Sie es einfach so:
var DB = require('../dal/base.js'); DB.query("select * from tasks", null, function (data, error) { callback(data, error); });
quelle
err
wahr ist? Sollte es nicht immer nochcallback
mit demnull
Parameter aufgerufen werden, um anzuzeigen, dass die Abfrage einen Fehler enthält?else
Bedingung wie die folgende hinzufügen :if (!err) { callback(rows, err); } else { callback(null, err); }
Andernfalls kann Ihre Anwendung hängen bleiben. Weilconnection.on('error', callback2)
sich nicht um alle "Fehler" kümmern. Vielen Dank!Wenn Sie mit einer Verbindung fertig sind, rufen Sie einfach an
connection.release()
und die Verbindung kehrt zum Pool zurück und kann von einer anderen Person erneut verwendet werden.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. }); });
Wenn Sie die Verbindung schließen und aus dem Pool entfernen möchten, verwenden Sie
connection.destroy()
stattdessen. Der Pool erstellt eine neue Verbindung, wenn das nächste Mal eine benötigt wird.Quelle : https://github.com/mysqljs/mysql
quelle
Mit dem Standard mysql.createPool () werden Verbindungen vom Pool träge erstellt. Wenn Sie den Pool so konfigurieren, dass bis zu 100 Verbindungen zulässig sind, aber immer nur 5 gleichzeitig verwendet werden, werden nur 5 Verbindungen hergestellt. Wenn Sie es jedoch für 500 Verbindungen konfigurieren und alle 500 verwenden, bleiben diese für die Dauer des Prozesses geöffnet, auch wenn sie inaktiv sind!
Das heißt, wenn Ihr MySQL Server max_connections 510 ist, stehen Ihrem System nur 10 mySQL-Verbindungen zur Verfügung, bis Ihr MySQL Server sie schließt (abhängig davon, auf was Sie Ihr wait_timeout eingestellt haben) oder Ihre Anwendung schließt! Die einzige Möglichkeit, sie freizugeben, besteht darin, die Verbindungen manuell über die Poolinstanz zu schließen oder den Pool zu schließen.
Das Modul mysql-connection-pool-manager wurde erstellt, um dieses Problem zu beheben und die Anzahl der Verbindungen abhängig von der Last automatisch zu skalieren. Inaktive Verbindungen werden geschlossen und inaktive Verbindungspools werden schließlich geschlossen, wenn keine Aktivität stattgefunden hat.
// 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();
Ref: https://www.npmjs.com/package/mysql-connection-pool-manager
quelle
Ich benutze immer connection.relase (); nach pool.getconnetion wie
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); } });
quelle