Fermer

janvier 20, 2020

Utilisation de MySQL avec Node.js et le client JavaScript mysql –


Les bases de données NoSQL sont plutôt populaires parmi les développeurs de nœuds, avec MongoDB (le «M» dans la pile MEAN) en tête du peloton. Cependant, lorsque vous démarrez un nouveau projet Node, vous ne devez pas simplement accepter Mongo comme choix par défaut. Le type de base de données que vous choisissez doit plutôt dépendre des exigences de votre projet. Si, par exemple, vous avez besoin de création de table dynamique ou d'insertions en temps réel, alors une solution NoSQL est la solution. Si votre projet concerne des requêtes et des transactions complexes, en revanche, une base de données SQL est beaucoup plus logique.

Dans ce didacticiel, nous verrons comment démarrer avec le module mysql – un client Node.js pour MySQL, écrit en JavaScript. J'expliquerai comment utiliser le module pour se connecter à une base de données MySQL et effectuer les opérations CRUD habituelles, avant de regarder les procédures stockées et d'échapper aux entrées utilisateur.

Cet article populaire a été mis à jour en 2020 pour refléter les pratiques actuelles d'utilisation de MySQL avec Node.js.

Démarrage rapide: Comment utiliser MySQL dans Node

Si vous êtes arrivé ici à la recherche d'un moyen rapide de démarrer avec MySQL dans Node, nous avons ce qu'il vous faut!

Voici comment utiliser MySQL dans Node en cinq étapes faciles:

  1. Créez un nouveau projet: mkdir mysql-test && cd mysql-test .
  2. Créez un package.json fichier: npm init -y .
  3. Installez le module mysql: npm install mysql .
  4. Créez un fichier app.js et copiez-le dans le fichier extrait ci-dessous (modification des espaces réservés selon le cas).
  5. Exécutez le fichier: node app.js . Observez un message "Connecté!".
 const mysql = require ('mysql');
const connection = mysql.createConnection ({
  hôte: «localhost»,
  utilisateur: 'utilisateur',
  mot de passe: 'mot de passe',
  base de données: 'nom de la base de données'
});
connection.connect ((err) => {
  if (err) throw err;
  console.log ('Connecté!');
});

Installation du module mysql

Voyons maintenant de plus près chacune de ces étapes.

 mkdir mysql-test
cd mysql-test
npm init -y
npm installer mysql

Tout d'abord, nous utilisons la ligne de commande pour créer un nouveau répertoire et y accéder. Ensuite, nous créons un fichier package.json à l'aide de la commande npm init -y . L'indicateur -y signifie que npm utilisera les valeurs par défaut sans passer par un processus interactif.

Cette étape suppose également que Node et npm sont installés sur votre système. Si ce n'est pas le cas, consultez cet article SitePoint pour savoir comment procéder: Installer plusieurs versions de Node.js à l'aide de nvm .

Après cela, nous installons le module mysql de npm et l'enregistrer en tant que dépendance de projet. Les dépendances de projet (par opposition à devDependencies) sont les packages requis pour l'exécution de l'application. Vous pouvez lire plus sur les différences entre les deux ici .

Si vous avez besoin d'aide pour utiliser npm, assurez-vous de consulter ce guide ou demandez-le dans nos forums .

Mise en route

Avant de nous connecter à une base de données, il est important que MySQL soit installé et configuré sur votre machine. Si ce n'est pas le cas, veuillez consulter les instructions d'installation sur leur page d'accueil .

La prochaine chose que nous devons faire est de créer une base de données et une table de base de données avec lesquelles travailler. Vous pouvez le faire en utilisant une interface graphique
telle que Adminer ou en utilisant la ligne de commande. Pour cet article, j'utiliserai une base de données appelée sitepoint et un tableau intitulé auteurs . Voici un vidage de la base de données, afin que vous puissiez être rapidement opérationnel si vous souhaitez suivre:

 CRÉER LA BASE DE DONNÉES sitepoint CHARACTER SET utf8 COLLATE utf8_general_ci;
USE sitepoint;

CRÉER des auteurs de TABLE (
  id int (11) NOT NULL AUTO_INCREMENT,
  nom varchar (50),
  ville varchar (50),
  CLÉ PRIMAIRE (id)
) MOTEUR = InnoDB DEFAULT CHARSET = utf8 AUTO_INCREMENT = 5;

INSÉRER DANS les auteurs (id, nom, ville) VALEURS
(1, «Michaela Lehr», «Berlin»),
(2, «Michael Wanyoike», «Nairobi»),
(3, «James Hibbard», «Munich»),
(4, «Karolina Gawron», «Wrocław»);

 Utilisation de MySQL avec Node.js et le client JavaScript mysql

Connexion à la base de données

Maintenant, créons un fichier appelé app.js dans notre mysql- tester le répertoire et voir comment se connecter à MySQL à partir de Node.js.

 const mysql = require ('mysql');

// Vous devez d'abord créer une connexion à la base de données
// Assurez-vous de remplacer «utilisateur» et «mot de passe» par les valeurs correctes
const con = mysql.createConnection ({
  hôte: «localhost»,
  utilisateur: 'utilisateur',
  mot de passe: 'mot de passe',
});

con.connect ((err) => {
  si (err) {
    console.log ('Erreur de connexion à Db');
    revenir;
  }
  console.log ('Connexion établie');
});

con.end ((err) => {
  // La connexion se termine normalement
  // Garantit que toutes les requêtes restantes sont exécutées
  // Envoie ensuite un paquet de sortie au serveur MySQL.
});

Ouvrez maintenant un terminal et entrez node app.js . Une fois la connexion établie avec succès, vous devriez pouvoir voir le message «Connexion établie» dans la console. Si quelque chose ne va pas (par exemple, vous entrez le mauvais mot de passe), un rappel est déclenché, auquel est transmise une instance de l'objet Erreur JavaScript ( err ). Essayez de vous connecter à la console pour voir les informations supplémentaires utiles qu'elle contient.

Utilisation de nodemon pour surveiller les fichiers pour les modifications

Exécution du noeud app.js à la main chaque fois que nous modifions notre le code va devenir un peu fastidieux, alors automatisons cela. Cette partie n'est pas nécessaire de suivre le reste du didacticiel, mais vous permettra certainement d'économiser quelques touches.

Commençons par installer le package nodemon . Il s'agit d'un outil qui redémarre automatiquement une application Node lorsque des modifications de fichiers dans un répertoire sont détectées:

 npm install --save-dev nodemon

Exécutez maintenant ./ node_modules / .bin / nodemon app.js et modifiez app.js . nodemon doit détecter la modification et redémarrer l'application.

Remarque: nous exécutons nodemon directement depuis le dossier node_modules . Vous pouvez également l'installer globalement ou créer un script npm pour le lancer.

Exécution de requêtes

Lecture

Maintenant que vous savez comment établir une connexion à une base de données MySQL à partir de Node.js, voyons comment pour exécuter des requêtes SQL. Nous allons commencer par spécifier le nom de la base de données ( sitepoint ) dans la commande createConnection :

 const con = mysql.createConnection ({
  hôte: «localhost»,
  utilisateur: 'utilisateur',
  mot de passe: 'mot de passe',
  base de données: 'sitepoint'
});

Une fois la connexion établie, nous utiliserons la variable con pour exécuter une requête sur la table de base de données auteurs :

 con.query ('SELECT * FROM auteurs ', (err, lignes) => {
  if (err) throw err;

  console.log ('Données reçues de Db:');
  console.log (lignes);
});

Lorsque vous exécutez app.js (en utilisant nodemon ou en tapant node app.js dans votre terminal), vous devriez pouvoir voir les données renvoyées par la base de données enregistrée au terminal:

 [ RowDataPacket { id: 1, name: 'Michaela Lehr', city: 'Berlin' },
  RowDataPacket { id: 2, name: 'Michael Wanyoike', city: 'Nairobi' },
  RowDataPacket { id: 3, name: 'James Hibbard', city: 'Munich' },
  RowDataPacket { id: 4, name: 'Karolina Gawron', city: 'Wrocław' } ]

Les données renvoyées par la base de données MySQL peuvent être analysées en faisant simplement une boucle sur l'objet rangées .

 row.forEach ((row) => {
  console.log (`$ {row.name} habite dans $ {row.city}`);
});

Cela vous donne ce qui suit:

 Michaela Lehr vit à Berlin
Michael Wanyoike vit à Nairobi
James Hibbard vit à Munich
Karolina Gawron vit à Wrocław

Création

Vous pouvez exécuter une requête d'insertion sur une base de données, comme ceci:

 const author = {nom: 'Craig Buckler', ville: 'Exmouth'};
con.query ('INSERT INTO auteurs SET?', auteur, (err, res) => {
  if (err) throw err;

  console.log ('ID dernière insertion:', res.insertId);
});

Notez comment nous pouvons obtenir l'ID de l'enregistrement inséré à l'aide du paramètre de rappel.

Mise à jour

De même, lors de l'exécution d'une requête de mise à jour, le nombre de lignes affectées peut être récupéré à l'aide de result.affectedRows :

 con.query (
  'MISE À JOUR des auteurs SET city =? Où ID =? ',
  ['Leipzig', 3],
  (err, résultat) => {
    if (err) throw err;

    console.log (`Changed $ {result.changedRows} row (s)`);
  }
);

Détruire

La même chose vaut pour une requête de suppression:

 con.query (
  'SUPPRIMER DES auteurs OERE id =?', [5](err, résultat) => {
    if (err) throw err;

    console.log (`Deleted $ {result.affectedRows} row (s)`);
  }
);

Utilisation avancée

J'aimerais terminer en examinant comment le module mysql gère les procédures stockées et l'échappement des entrées utilisateur.

Procédures stockées

En termes simples, une procédure stockée est un code SQL préparé que vous pouvez enregistrer dans une base de données, afin qu'il puisse être facilement réutilisé. Si vous avez besoin d'une mise à jour sur les procédures stockées, consultez ce didacticiel .

Créons une procédure stockée pour notre base de données sitepoint qui récupère tous les détails de l'auteur. Nous l'appellerons sp_get_authors . Pour ce faire, vous aurez besoin d'une sorte d'interface avec la base de données. J'utilise Adminer . Exécutez la requête suivante sur la base de données sitepoint en vous assurant que votre utilisateur dispose des droits d'administrateur sur le serveur MySQL:

 DELIMITER $$

CRÉER LA PROCÉDURE `sp_get_authors` ()
COMMENCER
  SELECT id, nom, ville FROM auteurs;
FIN $$

Ceci créera et stockera la procédure dans la base de données information_schema dans la table ROUTINES .

 Création d'une procédure stockée dans Adminer

Remarque: si la syntaxe du délimiteur vous semble étrange, il est expliqué ici .

Ensuite, établissez une connexion et utilisez l'objet de connexion pour appeler la procédure stockée comme indiqué:

 con.query ( 'CALL sp_get_authors ()', fonction (err, lignes) {
  if (err) throw err;

  console.log ('Données reçues de Db:');
  console.log (lignes);
});

Enregistrez les modifications et exécutez le fichier. Une fois qu'il est exécuté, vous devriez pouvoir visualiser les données renvoyées par la base de données:

 [ [ RowDataPacket { id: 1, name: 'Michaela Lehr', city: 'Berlin' },
    RowDataPacket { id: 2, name: 'Michael Wanyoike', city: 'Nairobi' },
    RowDataPacket { id: 3, name: 'James Hibbard', city: 'Leipzig' },
    RowDataPacket { id: 4, name: 'Karolina Gawron', city: 'Wrocław' },
  OkPacket {
    fieldCount: 0,
    affectedRows: 0,
    insertId: 0,
    serverStatus: 34,
    warningCount: 0,
    message: '',
    protocol41: true,
    changedRows: 0 } ]

Avec les données, il renvoie des informations supplémentaires, telles que le nombre de lignes affectées, insertId etc. Vous devez parcourir le 0e index des données renvoyées pour séparer les détails des employés des reste des informations:

 lignes [0] .forEach ((ligne) => {
  console.log (`$ {row.name} habite dans $ {row.city}`);
});

Cela vous donne ce qui suit:

 Michaela Lehr vit à Berlin
Michael Wanyoike vit à Nairobi
James Hibbard vit à Leipzig
Karolina Gawron vit à Wrocław

Considérons maintenant une procédure stockée qui nécessite un paramètre d'entrée:

 DELIMITER $$

CRÉER LA PROCÉDURE `sp_get_author_details` (
  dans author_id int
)
COMMENCER
  SELECT nom, ville FROM auteurs où id = author_id;
FIN $$

Nous pouvons passer le paramètre d'entrée lors d'un appel à la procédure stockée:

 con.query ('CALL sp_get_author_details (1)', (err, row) => {
  if (err) throw err;

  console.log ('Données reçues de Db:  n');
  console.log (lignes [0]);
});

Cela vous donne ce qui suit:

 [ RowDataPacket { name: 'Michaela Lehr', city: 'Berlin' } ]

La plupart du temps, lorsque nous essayons d'insérer un enregistrement dans la base de données, nous avons besoin que le dernier ID inséré soit renvoyé comme paramètre de sortie. Considérez la procédure stockée d'insertion suivante avec un paramètre out:

 DELIMITER $$

CRÉER LA PROCÉDURE `sp_insert_author` (
  out author_id int,
  dans author_name varchar (25),
  dans author_city varchar (25)
)
COMMENCER
  insérer dans les auteurs (nom, ville)
  valeurs (nom_auteur, ville_auteur);
  set author_id = LAST_INSERT_ID ();
FIN $$

Pour effectuer un appel de procédure avec un paramètre out, nous devons d'abord activer plusieurs appels lors de la création de la connexion. Modifiez donc la connexion en définissant l'exécution d'instructions multiples sur true :

 const con = mysql.createConnection ({
  hôte: «localhost»,
  utilisateur: 'utilisateur',
  mot de passe: 'mot de passe',
  base de données: 'sitepoint',
  multipleStatements: true
});

Ensuite, lors d'un appel à la procédure, définissez un paramètre out et passez-le:

 con.query (
  "SET @author_id = 0; CALL sp_insert_author (@author_id, 'Craig Buckler', 'Exmouth'); SELECT @author_id",
  (err, lignes) => {
    if (err) throw err;

    console.log ('Données reçues de Db:  n');
    console.log (lignes);
  }
);

Comme indiqué dans le code ci-dessus, nous avons défini un paramètre @author_id out et l'avons transmis lors d'un appel à la procédure stockée. Une fois l'appel effectué, nous devons sélectionner le paramètre out pour accéder à l'ID renvoyé.

Exécutez app.js . En cas d'exécution réussie, vous devriez pouvoir voir le paramètre de sortie sélectionné ainsi que diverses autres informations. les lignes [2] devraient vous donner accès au paramètre de sortie sélectionné:

 [ RowDataPacket { '@author_id': 6 } ]]

Remarque: Pour supprimer une procédure stockée, vous devez exécuter la commande DROP PROCEDURE ; par rapport à la base de données pour laquelle vous l'avez créée.

Échappement de l'entrée utilisateur

Pour pour éviter les attaques par injection SQL, vous devez toujours échapper toutes les données que vous recevez des utilisateurs avant de les utiliser dans une requête SQL. Montrons pourquoi:

 const userSubmittedVariable = '1';

con.query (
  `SELECT * FROM auteurs WHERE id = $ {userSubmittedVariable}`,
  (err, lignes) => {
    if (err) throw err;
    console.log (lignes);
  }
);

Cela semble assez inoffensif et renvoie même le résultat correct:

 {id: 1, nom: 'Michaela Lehr', ville: 'Berlin'}

Cependant, essayez de changer la userSubmittedVariable en ceci:

 const userSubmittedVariable = '1 OR 1 = 1';

Nous avons soudainement accès à l'ensemble des données. Maintenant, changez-le en ceci:

 const userSubmittedVariable = '1; Auteurs DROP TABLE;

Nous avons maintenant des ennuis!

La bonne nouvelle est que l'aide est à portée de main. Il vous suffit d'utiliser la méthode mysql.escape :

 con.query (
  `SELECT * FROM auteurs WHERE id = $ {mysql.escape (userSubmittedVariable)}`,
  (err, lignes) => {
    if (err) throw err;
    console.log (lignes);
  }
);

Vous pouvez également utiliser un espace réservé de point d'interrogation, comme nous l'avons fait dans les exemples au début de l'article:

 con.query (
  'SELECT * FROM auteurs WHERE id =?',
  [userSubmittedVariable],
  (err, lignes) => {
    if (err) throw err;
    console.log (lignes);
  }
);

Pourquoi ne pas simplement utiliser un ORM?

Avant d'entrer dans le pour et le contre de cette approche, prenons une seconde pour voir ce que sont les ORM. Ce qui suit est tiré de une réponse sur Stack Overflow :

Object-Relational Mapping (ORM) est une technique qui vous permet d'interroger et de manipuler les données d'une base de données en utilisant un paradigme orienté objet. Quand on parle d'ORM, la plupart des gens font référence à une bibliothèque qui implémente la technique de mappage relationnel objet, d'où l'expression «un ORM».

Cela signifie donc que vous écrivez la logique de votre base de données dans le langage spécifique au domaine de l'ORM, par opposition à l'approche vanille que nous avons adoptée jusqu'à présent. Pour vous donner une idée de ce à quoi cela pourrait ressembler, voici un exemple utilisant Sequelize qui interroge la base de données pour tous les auteurs et les connecte à la console:

 const sequelize = new Sequelize ('sitepoint' , 'mot de passe de l'utilisateur', {
  hôte: «localhost»,
  dialecte: 'mysql'
});

const Author = sequelize.define ('author', {
  Nom: {
    type: Sequelize.STRING,
  },
  ville: {
    type: Sequelize.STRING
  },
}, {
  horodatages: faux
});

Author.findAll (). Then (auteurs => {
  console.log ("Tous les auteurs:", JSON.stringify (auteurs, null, 4));
});

Le fait que l'utilisation ou non d'un ORM ait du sens pour vous dépendra beaucoup de ce sur quoi vous travaillez et avec qui. D'une part, ORMS a tendance à rendre les développeurs plus productifs, en partie en soustrayant une grande partie du SQL afin que tout le monde dans l'équipe n'ait pas besoin de savoir comment écrire des requêtes spécifiques aux bases de données super efficaces. Il est également facile de passer à un autre logiciel de base de données, car vous développez vers une abstraction.

D'un autre côté, cependant, il est possible d'écrire du SQL vraiment désordonné et inefficace du fait de ne pas comprendre comment l'ORM fait quoi Cela fait. Les performances sont également un problème dans la mesure où il est beaucoup plus facile d'optimiser les requêtes qui n'ont pas à passer par l'ORM.

Quel que soit le chemin que vous choisissez, mais si c'est une décision que vous êtes en train de prendre , consultez ce fil de débordement de pile: Pourquoi devriez-vous utiliser un ORM? . Consultez également cet article sur SitePoint: 3 ORM JavaScript que vous ne connaissez peut-être pas .

Conclusion

Dans ce didacticiel, nous avons installé le client mysql pour Node.js et l'a configuré pour se connecter à une base de données. Nous avons également vu comment effectuer des opérations CRUD, travailler avec des instructions préparées et échapper les entrées utilisateur pour atténuer les attaques par injection SQL. Et pourtant, nous n'avons fait qu'effleurer la surface de ce que propose le client mysql. Pour des informations plus détaillées, je recommande de lire la documentation officielle

Et n'oubliez pas que le module mysql n'est pas le seul spectacle en ville. Il existe également d'autres options, comme la populaire node-mysql2 .




Source link