Contactez-nous

Connexion à une base de données MySQL avec le module mysql

Apprenez a connecter votre application Node.js a une base de donnees MySQL en utilisant le module `mysql2`, en creant des pools de connexions et en executant des requetes SQL.

Interagir avec MySQL depuis Node.js : le besoin d'un pilote

MySQL est l'un des systèmes de gestion de bases de données relationnelles (SGBDR) les plus populaires au monde, largement utilisé pour stocker les données d'applications web. Pour permettre à votre application Node.js de communiquer avec une base de données MySQL (envoyer des requêtes SQL, récupérer des résultats), vous avez besoin d'un intermédiaire : un pilote ou driver spécifique à MySQL pour Node.js.

Plusieurs packages npm existent pour remplir ce rôle. Historiquement, le package `mysql` (mysqljs/mysql) était très utilisé. Cependant, aujourd'hui, le package `mysql2` (sidorares/node-mysql2) est généralement préféré et recommandé. Il offre une API largement compatible avec `mysql`, mais avec de meilleures performances, un support natif des Promesses (facilitant l'usage avec `async/await`), et une gestion plus robuste des instructions préparées (prepared statements), ce qui est important pour la sécurité et l'efficacité.

Ce guide se concentrera sur l'utilisation de `mysql2` pour établir une connexion fiable et efficace entre votre application Node.js et votre base de données MySQL.

Installation du pilote `mysql2`

Comme pour tout package externe, la première étape est d'installer `mysql2` comme dépendance de votre projet Node.js. Assurez-vous d'être à la racine de votre projet (où se trouve votre `package.json`) dans votre terminal, puis exécutez :

npm install mysql2

Ou si vous utilisez Yarn :

yarn add mysql2

Cette commande télécharge le package `mysql2` et l'ajoute à vos dépendances dans `package.json`. Vous êtes maintenant prêt à l'utiliser dans votre code.

Methodes de connexion : connexion unique vs. pool de connexions

Le module `mysql2` offre principalement deux façons d'établir une connexion :

  1. Connexion unique (`createConnection`) : Crée une seule connexion directe à la base de données. Chaque opération (ouverture, authentification, requête, fermeture) a un certain coût. Cette méthode peut convenir pour des scripts simples ou des tâches ponctuelles, mais elle est fortement déconseillée pour les applications web. Gérer manuellement le cycle de vie de chaque connexion pour chaque requête utilisateur est inefficace et peut rapidement épuiser les ressources du serveur de base de données.
  2. Pool de connexions (`createPool`) : C'est la méthode recommandée pour les applications web et les serveurs. Un pool de connexions est un ensemble de connexions pré-établies et maintenues par le pilote. Lorsqu'une partie de votre application a besoin d'interagir avec la base de données, elle "emprunte" une connexion disponible du pool, l'utilise, puis la "rend" au pool pour qu'elle puisse être réutilisée par une autre partie de l'application. Cela évite le coût de création/fermeture de connexion pour chaque requête, améliore considérablement les performances et gère efficacement les ressources.

Nous nous concentrerons sur l'utilisation des pools de connexions, car c'est la pratique standard en production.

Creer et configurer un pool de connexions

Pour créer un pool, vous utilisez la fonction `mysql.createPool()` du module `mysql2`. Vous devez lui fournir un objet de configuration contenant les informations nécessaires pour se connecter à votre base de données MySQL.

Pour utiliser l'API basée sur les Promesses (recommandée avec `async/await`), nous importerons spécifiquement `mysql2/promise`.

// Importer la version 'promise' de mysql2
const mysql = require('mysql2/promise');

// Configuration de la connexion
// !! NE JAMAIS HARDCODER LES IDENTIFIANTS EN PRODUCTION !!
// Utilisez des variables d'environnement (process.env)
const dbConfig = {
  host: process.env.DB_HOST || 'localhost',      // Adresse du serveur MySQL
  user: process.env.DB_USER || 'votre_user',    // Nom d'utilisateur MySQL
  password: process.env.DB_PASSWORD || 'votre_mot_de_passe', // Mot de passe MySQL
  database: process.env.DB_NAME || 'votre_database', // Nom de la base de données
  waitForConnections: true, // Attendre si toutes les connexions sont utilisées
  connectionLimit: 10,      // Nombre maximum de connexions dans le pool
  queueLimit: 0             // Nombre maximum de demandes en file d'attente (0 = illimité)
};

// Créer le pool de connexions
let pool;
try {
   pool = mysql.createPool(dbConfig);
   console.log('Pool de connexions MySQL créé avec succès.');

   // Vous pouvez tester la connexion (optionnel)
   // const connection = await pool.getConnection();
   // console.log('Connexion au pool réussie !');
   // connection.release(); // Libérer la connexion

} catch (error) {
   console.error('Erreur lors de la création du pool MySQL:', error);
   // Gérer l'erreur (arrêter l'app ?, logger ?)
   process.exit(1); // Arrêter l'application si le pool ne peut être créé
}

// Exporter le pool pour l'utiliser ailleurs dans l'application (si besoin)
// module.exports = pool;

Note de sécurité cruciale : L'exemple ci-dessus montre où placer les identifiants, mais il est impératif de ne jamais les écrire directement dans votre code source (hardcoding). Utilisez des variables d'environnement (via `process.env` comme suggéré, souvent chargées depuis un fichier `.env` avec des packages comme `dotenv`) ou d'autres systèmes de gestion de secrets pour stocker ces informations sensibles en production.

Executer des requetes SQL

Une fois le pool créé et disponible (par exemple, exporté depuis un fichier de configuration), vous pouvez l'utiliser pour exécuter des requêtes SQL. Avec `mysql2/promise`, les méthodes retournent des Promesses, ce qui s'intègre parfaitement avec `async/await`.

Les deux méthodes principales sont :

  • `pool.query(sql, [values])` : Exécute la requête SQL. Si vous fournissez des valeurs dans le tableau `[values]`, elles seront échappées pour prévenir les injections SQL basiques, mais il est généralement préférable d'utiliser des instructions préparées.
  • `pool.execute(sql, [values])` : Utilise des instructions préparées (prepared statements) côté serveur MySQL. C'est plus sécurisé contre les injections SQL et souvent plus performant pour les requêtes exécutées plusieurs fois avec des paramètres différents. C'est la méthode recommandée pour exécuter des requêtes avec des données variables (venant de l'utilisateur). Les `?` dans la chaîne `sql` servent de marqueurs (`placeholders`) pour les valeurs fournies dans le tableau `[values]`.

Exemple d'exécution d'une requête `SELECT` avec `execute` :

// Supposons que 'pool' a été créé et importé

async function getUserById(userId) {
  if (!pool) {
    throw new Error('Le pool de connexions n\'est pas initialisé.');
  }
  
  const sql = 'SELECT id, username, email FROM users WHERE id = ?';
  try {
    // Exécuter la requête préparée
    // Le résultat est un tableau [rows, fields]
    const [rows, fields] = await pool.execute(sql, [userId]);

    if (rows.length > 0) {
      console.log('Utilisateur trouvé:', rows[0]);
      return rows[0]; // Retourne le premier (et unique) utilisateur trouvé
    } else {
      console.log(`Aucun utilisateur trouvé avec l'ID ${userId}`);
      return null;
    }
  } catch (error) {
    console.error(`Erreur lors de la récupération de l'utilisateur ${userId}:`, error);
    throw error; // Propager l'erreur pour une gestion centralisée
  }
}

// Exemple d'appel
async function main() {
    try {
        const user = await getUserById(1);
        // Faire quelque chose avec l'utilisateur...
    } catch (error) {
        console.error('Une erreur est survenue dans main:', error);
    }
}

// main();

De manière similaire, vous utiliseriez `INSERT`, `UPDATE`, `DELETE` avec `pool.execute()` pour modifier des données, en passant les valeurs à insérer ou mettre à jour dans le tableau `[values]`.

Gestion des erreurs et fermeture du pool

Il est essentiel de gérer les erreurs qui peuvent survenir lors des interactions avec la base de données. Les méthodes de `mysql2/promise` lèveront des erreurs en cas de problème (connexion impossible, syntaxe SQL incorrecte, violation de contrainte, etc.). Utilisez des blocs `try...catch` autour de vos appels `await pool.execute(...)` ou `await pool.query(...)` pour intercepter ces erreurs et y réagir de manière appropriée (logger l'erreur, renvoyer une réponse d'erreur HTTP 500, etc.).

Le pool de connexions gère automatiquement l'ouverture et la fermeture des connexions individuelles. Cependant, lorsque votre application Node.js s'arrête proprement (par exemple, lors d'un déploiement ou d'un arrêt manuel), il est recommandé de fermer le pool pour libérer toutes les connexions et ressources associées. Cela se fait avec la méthode `pool.end()`.

async function shutdown() {
  if (pool) {
    console.log('Fermeture du pool de connexions MySQL...');
    try {
      await pool.end();
      console.log('Pool fermé avec succès.');
    } catch (error) {
      console.error('Erreur lors de la fermeture du pool:', error);
    }
  }
}

// Appeler shutdown() lors de l'arrêt gracieux de l'application
// Exemple: écouter les signaux SIGINT (Ctrl+C) ou SIGTERM
process.on('SIGINT', async () => {
  await shutdown();
  process.exit(0);
});
process.on('SIGTERM', async () => {
    await shutdown();
    process.exit(0);
});

Conclusion : une fondation solide pour les donnees relationnelles

Le module `mysql2`, en particulier avec son API de Promesses (`mysql2/promise`) et l'utilisation de pools de connexions (`createPool`), fournit une manière moderne, performante et sécurisée d'interagir avec les bases de données MySQL depuis Node.js.

En maîtrisant la création de pools, l'exécution de requêtes préparées via `pool.execute()`, la gestion des erreurs et la fermeture propre du pool, vous disposez des outils nécessaires pour intégrer efficacement la persistance des données relationnelles dans vos applications serveur Node.js.