webentwicklung-frage-antwort-db.com.de

node.js + MySQL-Verbindungspooling

Ich versuche herauszufinden, wie ich meine Anwendung so strukturieren kann, dass sie MySQL am effizientesten nutzt. Ich verwende node-mysql-Modul. Andere Threads hier schlagen vor, das Verbindungspooling zu verwenden, also habe ich ein kleines Modul mysql.js eingerichtet

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 dann die Datenbank

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, abgesehen von den sehr einfachen, bei denen alles im main app.js-Skript erledigt wird.

Soll ich nach jeder Abfrage immer connection.end () verwenden? Was ist, wenn ich es irgendwo vergesse?

Wie schreibe ich den Export-Teil meines mysql-Moduls um, um nur eine Verbindung zurückzugeben, damit ich nicht jedes Mal getConnection () schreiben muss?

57
kasztelan

Es ist ein guter Ansatz.

Wenn Sie nur eine Verbindung erhalten möchten, fügen Sie dem Modul, in dem sich der Pool befindet, folgenden Code hinzu:

var getConnection = function(callback) {
    pool.getConnection(function(err, connection) {
        callback(err, connection);
    });
};

module.exports = getConnection;

Sie müssen immer noch getConnection schreiben. Sie können die Verbindung jedoch beim ersten Aufruf im Modul speichern.

Vergessen Sie nicht, die Verbindung zu beenden, wenn Sie damit fertig sind:

connection.release();
44
Klaasvaak

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;
            }
        };
    }
};

Fordern Sie es so an:

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});
          });
11
Felipe Jimenez

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);
});
6
Sagi Tsofan

Sie sollten pool.getConnection() vermeiden, wenn Sie können. Wenn Sie pool.getConnection() aufrufen, müssen Sie müssen connection.release() aufrufen, wenn Sie die Verbindung hergestellt haben. Andernfalls bleibt Ihre Anwendung unwiderruflich darauf warten, dass die Verbindungen zum Pool zurückgegeben werden, sobald Sie das Verbindungslimit erreicht haben.

Für einfache Abfragen können Sie pool.query() verwenden. Diese Abkürzung ruft automatisch connection.release() auf - 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 pool.getConnection() verwenden. Diese Fälle umfassen:

  1. Mehrere Abfragen innerhalb einer Transaktion durchführen.
  2. Gemeinsame Nutzung von Datenobjekten wie temporären Tabellen zwischen nachfolgenden Abfragen.

Wenn Sie pool.getConnection() verwenden müssen, stellen Sie sicher, dass Sie connection.release() mit einem Muster aufrufen, das dem folgenden ähnelt:

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 Promises und das useAsync()-Muster. Dieses Muster in Kombination mit async/await macht es sehr viel schwieriger, die Verbindung release() aus Versehen zu vergessen, da es aus Ihrem lexikalischen Bereich einen automatischen Aufruf von .release() macht:

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}`);
}
3
binki

Wenn Sie mit der Verbindung fertig sind, rufen Sie einfach connection.release() auf, und die Verbindung wird wieder in den Pool zurückkehren, um von einer anderen Person erneut verwendet zu 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 stattdessen connection.destroy(). Der Pool erstellt beim nächsten Mal eine neue Verbindung.

Source: https://github.com/mysqljs/mysql

1

Mit dem Standard mysql.createPool () werden die Verbindungen vom Pool faul erstellt. Wenn Sie den Pool so konfigurieren, dass er bis zu 100 Verbindungen zulässt, aber immer nur 5 gleichzeitig verwenden, 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 offen, selbst wenn sie nicht verwendet werden.

Das bedeutet, wenn Ihr MySQL Server max_connections den Wert 510 hat, stehen Ihrem System nur 10 MySQL-Verbindungen zur Verfügung, bis Ihr MySQL Server diese Verbindungen (abhängig davon, was Sie für wait_timeout festgelegt haben) oder Ihre Anwendung schließt! Sie können sie nur freigeben, indem Sie die Verbindungen manuell über die Poolinstanz oder den Pool schließen.

das Modul mysql-connection-pool-manager wurde erstellt, um dieses Problem zu beheben und die Anzahl der von der Last abhängigen Verbindungen automatisch zu skalieren. Inaktive Verbindungen werden geschlossen und inaktive Verbindungspools werden schließlich geschlossen, wenn keine Aktivität erfolgt ist.

    // 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

0
Yordan