web-dev-qa-db-fra.com

pool de connexions node.js + mysql

J'essaie de comprendre comment structurer mon application pour utiliser MySQL de la manière la plus efficace. J'utilise le module node-mysql. D'autres threads ici suggérés d'utiliser le pool de connexion afin que je mette en place un petit module mysql.js

var mysql = require('mysql');

var pool  = mysql.createPool({
    Host     : 'localhost',
    user     : 'root',
    password : 'root',
    database : 'guess'
});

exports.pool = pool;

Maintenant, chaque fois que je veux interroger mysql, j'ai besoin de ce module, puis interroger la base de données

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

Est-ce une bonne approche? Je ne pouvais pas vraiment trouver trop d'exemples d'utilisation de connexions mysql en plus d'un très simple où tout est fait dans le script principal de app.js, donc je ne sais pas vraiment quelle est la convention/les meilleures pratiques.

Devrais-je toujours utiliser connection.end () après chaque requête? Et si je l'oublie quelque part?

Comment réécrire la partie exports de mon module mysql pour ne renvoyer qu'une connexion afin que je n'ai pas à écrire getConnection () à chaque fois?

57
kasztelan

C'est une bonne approche.

Si vous souhaitez simplement établir une connexion, ajoutez le code suivant à votre module contenant le pool:

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

module.exports = getConnection;

Vous devez toujours écrire à getConnection à chaque fois. Mais vous pouvez enregistrer la connexion dans le module la première fois que vous l’obtenez.

N'oubliez pas de mettre fin à la connexion lorsque vous avez fini de l'utiliser:

connection.release();
44
Klaasvaak

Vous trouverez ce wrapper utile :)

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

Exigez-le, utilisez-le comme ceci:

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

J'utilise cette connexion de classe de base avec 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;

Il suffit de l'utiliser comme ça:

var DB = require('../dal/base.js');

DB.query("select * from tasks", null, function (data, error) {
   callback(data, error);
});
6
Sagi Tsofan

Vous devriez éviter d'utiliser pool.getConnection() si vous le pouvez. Si vous appelez pool.getConnection(), vous devez appeler connection.release() lorsque vous avez terminé l’utilisation de la connexion. Sinon, votre application restera bloquée dans l'attente permanente du retour des connexions au pool une fois que vous aurez atteint la limite de connexion.

Pour les requêtes simples, vous pouvez utiliser pool.query(). Ce raccourci appelle automatiquement connection.release() pour vous, même en cas d'erreur.

function doSomething(cb) {
  pool.query('SELECT 2*2 "value"', (ex, rows) => {
    if (ex) {
      cb(ex);
    } else {
      cb(null, rows[0].value);
    }
  });
}

Cependant, dans certains cas, vous devez utiliser pool.getConnection(). Ces cas incluent:

  1. Faire plusieurs requêtes dans une transaction.
  2. Partage d'objets de données tels que des tables temporaires entre les requêtes suivantes.

Si vous devez utiliser pool.getConnection(), assurez-vous d'appeler connection.release() en utilisant un modèle semblable à celui ci-dessous:

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

Personnellement, je préfère utiliser Promises et le modèle useAsync(). Ce modèle associé à async/await rend beaucoup plus difficile l’oubli accidentel de release() la connexion car il transforme votre portée lexicale en appel automatique à .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}`);
}
3
binki

Lorsque vous avez terminé avec une connexion, appelez simplement connection.release() et la connexion reviendra dans le pool, prête à être utilisée à nouveau par quelqu'un d'autre.

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

Si vous souhaitez fermer la connexion et la supprimer du pool, utilisez plutôt connection.destroy(). Le pool créera une nouvelle connexion lors de la prochaine connexion.

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

1
Mukesh Chapagain

En utilisant la fonction standard mysql.createPool (), les connexions sont créées paresseusement par le pool. Si vous configurez le pool pour permettre jusqu'à 100 connexions, mais que vous n'en utilisiez que 5 simultanément, seules 5 connexions seront établies. Cependant, si vous le configurez pour 500 connexions et utilisez les 500, elles resteront ouvertes pendant toute la durée du processus, même si elles sont inactives!

Cela signifie que si votre max_connections de serveur MySQL est 510, votre système ne disposera que de 10 connexions mySQL disponibles jusqu'à ce que votre serveur MySQL les ferme (dépend de ce que vous avez défini sur wait_timeout) ou de votre application se ferme! La seule façon de les libérer consiste à fermer manuellement les connexions via l'instance de pool ou à fermer le pool.

le module mysql-connection-pool-manager a été créé pour résoudre ce problème et redimensionner automatiquement le nombre de connexions en fonction de la charge. Les connexions inactives sont fermées et les pools de connexions inactifs sont éventuellement fermés s'il n'y a pas eu d'activité.

    // 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();

Réf.: https://www.npmjs.com/package/mysql-connection-pool-manager

0
Yordan