105 votes

node.js + pooling de connexion 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 fils de discussion ici ont suggéré d'utiliser le pooling de connexion, donc j'ai mis 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 et j'interroge 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 n'ai pas vraiment trouvé beaucoup d'exemples d'utilisation de connexions mysql à part un exemple très simple où tout est fait dans le fichier principal app.js script donc je ne sais pas vraiment quelles sont les conventions / les meilleures pratiques.

Dois-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 retourner qu'une connexion afin de ne pas avoir à écrire getConnection() à chaque fois ?

78voto

Klaasvaak Points 1433

C'est une bonne approche.

Si vous voulez simplement obtenir une connexion, ajoutez le code suivant à votre module où se trouve 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 pourriez 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();

45voto

binki Points 479

Vous devez éviter d'utiliser pool.getConnection() si vous le pouvez. Si vous appelez pool.getConnection() vous doit appelez connection.release() lorsque vous avez terminé d'utiliser la connexion. Sinon, votre application restera coincée à attendre éternellement que les connexions soient renvoyées dans le pool une fois que vous aurez atteint la limite de connexion.

Pour les requêtes simples, vous pouvez utiliser pool.query() . Ce raccourci appellera 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 comprennent :

  • Effectuer plusieurs requêtes dans une même transaction.
  • Partager des objets de données tels que des tables temporaires entre des requêtes ultérieures.

Si vous devez utiliser pool.getConnection() assurez-vous d'appeler connection.release() en utilisant un modèle similaire à 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);
                  });
                }
              });
            }
          });
        }
      });
    }
  });
}

Je préfère personnellement utiliser Promise et les useAsync() modèle. Ce modèle, combiné à async / await fait qu'il est beaucoup plus difficile d'oublier accidentellement de release() la connexion parce que cela transforme votre scoping lexical en un 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}`);
}

16voto

Felipe Jimenez Points 161

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

14voto

Sagi Tsofan Points 137

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

Utilisez-le juste comme ça :

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

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

2voto

chapagain Points 6536

Lorsque vous avez terminé une connexion, il suffit d'appeler connection.release() et la connexion retournera 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 retirer du pool, utilisez la commande suivante connection.destroy() à la place. Le pool créera une nouvelle connexion la prochaine fois qu'il en aura besoin.

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

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X