Logotipo de Zephyrnet

Usando MySQL con Node.js y el Cliente JavaScript mysql

Fecha:

Las bases de datos NoSQL son bastante populares entre los desarrolladores de Node, con MongoDB (la "M" en la pila MEAN) a la cabeza. Sin embargo, al iniciar un nuevo proyecto de Node, no debe aceptar Mongo como la opción predeterminada. Más bien, el tipo de base de datos que elija debe depender de los requisitos de su proyecto. Si, por ejemplo, necesita la creación de tablas dinámicas o inserciones en tiempo real, entonces una solución NoSQL es el camino a seguir. Si su proyecto trata con consultas y transacciones complejas, por otro lado, una base de datos SQL tiene mucho más sentido.

En este tutorial, veremos cómo comenzar con el módulo mysql - un cliente Node.js para MySQL, escrito en JavaScript. Explicaré cómo usar el módulo para conectarse a una base de datos MySQL y realizar las operaciones CRUD habituales, antes de mirar los procedimientos almacenados y escapar de la entrada del usuario.

Este popular artículo se actualizó en 2020 para reflejar las prácticas actuales de uso de MySQL con Node.js. Para más información sobre MySQL, lea Inicie MySQL.

Inicio rápido: cómo usar MySQL en el nodo

Si ha llegado aquí en busca de una forma rápida de comenzar a utilizar MySQL en Node, ¡lo tenemos cubierto!

Aquí se explica cómo usar MySQL en Node en cinco sencillos pasos:

  1. Crea un nuevo proyecto: mkdir mysql-test && cd mysql-test.
  2. Créar un package.json archivo: npm init -y.
  3. Instale el módulo mysql: npm install mysql.
  4. Crear una app.js archivo y copia en el fragmento a continuación (editando los marcadores de posición según corresponda).
  5. Ejecute el archivo: node app.js. Observe un "¡Conectado!" mensaje.
const mysql = require('mysql');
const connection = mysql.createConnection({ host: 'localhost', user: 'user', password: 'password', database: 'database name'
});
connection.connect((err) => { if (err) throw err; console.log('Connected!');
});

Instalación del módulo mysql

Ahora echemos un vistazo más de cerca a cada uno de esos pasos.

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

En primer lugar, usamos la línea de comandos para crear un nuevo directorio y navegar hasta él. Entonces estamos creando un package.json archivo usando el comando npm init -y. -y flag significa que npm usará los valores predeterminados sin pasar por un proceso interactivo.

Este paso también asume que tiene Node y npm instalados en su sistema. Si este no es el caso, consulte este artículo de SitePoint para averiguar cómo hacerlo: Instale múltiples versiones de Node.js usando nvm.

Después de eso, instalaremos el módulo mysql de npm y guardarlo como una dependencia del proyecto. Las dependencias del proyecto (a diferencia de devDependencies) son los paquetes necesarios para que se ejecute la aplicación. Puedes leer más sobre las diferencias entre los dos aquí.

Si necesita más ayuda para usar npm, asegúrese de consultar esta guíao pregunta en nuestros foros.

Cómo Empezar

Antes de comenzar a conectarnos a una base de datos, es importante que tenga MySQL instalado y configurado en su máquina. Si este no es el caso, consulte el instrucciones de instalación en su página de inicio.

Lo siguiente que debemos hacer es crear una base de datos y una tabla de base de datos para trabajar. Puede hacer esto usando un
interfaz gráfica, como Administrador, o usando la línea de comando. Para este artículo utilizaré una base de datos llamada sitepoint y una mesa llamada authors. Aquí hay un volcado de la base de datos, para que pueda comenzar a trabajar rápidamente si desea seguir adelante:

CREATE DATABASE sitepoint CHARACTER SET utf8 COLLATE utf8_general_ci;
USE sitepoint; CREATE TABLE authors ( id int(11) NOT NULL AUTO_INCREMENT, name varchar(50), city varchar(50), PRIMARY KEY (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=5 ; INSERT IGNORE INTO authors (id, name, city) VALUES
(1, 'Michaela Lehr', 'Berlin'),
(2, 'Michael Wanyoike', 'Nairobi'),
(3, 'James Hibbard', 'Munich'),
(4, 'Karolina Gawron', 'Wrocław');

Usando MySQL con Node.js y el cliente JavaScript mysql

Conectarse a la base de datos

Ahora, creemos un archivo llamado app.js en nuestro mysql-test directorio y vea cómo conectarse a MySQL desde Node.js.

const mysql = require('mysql'); // First you need to create a connection to the database
// Be sure to replace 'user' and 'password' with the correct values
const con = mysql.createConnection({ host: 'localhost', user: 'user', password: 'password',
}); con.connect((err) => { if(err){ console.log('Error connecting to Db'); return; } console.log('Connection established');
}); con.end((err) => { // The connection is terminated gracefully // Ensures all remaining queries are executed // Then sends a quit packet to the MySQL server.
});

Ahora abre una terminal y entra node app.js. Una vez que la conexión se haya establecido correctamente, debería poder ver el mensaje "Conexión establecida" en la consola. Si algo sale mal (por ejemplo, ingresa la contraseña incorrecta), se activa una devolución de llamada, a la que se le pasa una instancia del objeto Error de JavaScript (err). Intente registrar esto en la consola para ver qué información adicional útil contiene.

Uso de nodemon para observar los archivos en busca de cambios

Correr node app.js a mano, cada vez que hagamos un cambio en nuestro código se volverá un poco tedioso, así que automaticemos eso. No es necesario seguir esta parte junto con el resto del tutorial, pero sin duda le ahorrará algunas pulsaciones de teclas.

Comencemos instalando un Nodemon paquete. Esta es una herramienta que reinicia automáticamente una aplicación Node cuando se detectan cambios de archivo en un directorio:

npm install --save-dev nodemon

Ahora corre ./node_modules/.bin/nodemon app.js y hacer un cambio a app.js. nodemon debería detectar el cambio y reiniciar la aplicación.

Nota: estamos ejecutando nodemon directamente desde el node_modules carpeta. También puede instalarlo globalmente o crear un script npm para iniciarlo.

Ejecutando consultas

Reading

Ahora que sabe cómo establecer una conexión a una base de datos MySQL desde Node.js, veamos cómo ejecutar consultas SQL. Comenzaremos especificando el nombre de la base de datos (sitepoint) En la createConnection mando:

const con = mysql.createConnection({ host: 'localhost', user: 'user', password: 'password', database: 'sitepoint'
});

Una vez establecida la conexión, usaremos el con variable para ejecutar una consulta en la tabla de la base de datos authors:

con.query('SELECT * FROM authors', (err,rows) => { if(err) throw err; console.log('Data received from Db:'); console.log(rows);
});

Cuando corres app.js (ya sea usando nodemon o escribiendo node app.js en su terminal), debería poder ver los datos devueltos desde la base de datos registrada en el 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' } ]

Los datos devueltos de la base de datos MySQL se pueden analizar simplemente haciendo un bucle sobre el rows objeto.

rows.forEach( (row) => { console.log(`${row.name} lives in ${row.city}`);
});

Esto le da lo siguiente:

Michaela Lehr lives in Berlin
Michael Wanyoike lives in Nairobi
James Hibbard lives in Munich
Karolina Gawron lives in Wrocław

Creamos

Puede ejecutar una consulta de inserción en una base de datos, así:

const author = { name: 'Craig Buckler', city: 'Exmouth' };
con.query('INSERT IGNORE INTO authors SET ?', author, (err, res) => { if(err) throw err; console.log('Last insert ID:', res.insertId);
});

Tenga en cuenta cómo podemos obtener el ID del registro insertado utilizando el parámetro de devolución de llamada.

Actualización de

De manera similar, al ejecutar una consulta de actualización, el número de filas afectadas se puede recuperar usando result.affectedRows:

con.query( 'UPDATE authors SET city = ? Where ID = ?', ['Leipzig', 3], (err, result) => { if (err) throw err; console.log(`Changed ${result.changedRows} row(s)`); }
);

Destruyendo

Lo mismo ocurre con una consulta de eliminación:

con.query( 'DELETE FROM authors WHERE id = ?', [5], (err, result) => { if (err) throw err; console.log(`Deleted ${result.affectedRows} row(s)`); }
);

Uso avanzado

Me gustaría terminar mirando cómo el módulo mysql maneja los procedimientos almacenados y el escape de la entrada del usuario.

Procedimientos almacenados

En pocas palabras, un procedimiento almacenado es un código SQL preparado que puede guardar en una base de datos, de modo que pueda reutilizarse fácilmente. Si necesita un repaso sobre los procedimientos almacenados, consulte este tutorial.

Creemos un procedimiento almacenado para nuestro sitepoint base de datos que obtiene todos los detalles del autor. Lo llamaremos sp_get_authors. Para hacer esto, necesitará algún tipo de interfaz para la base de datos. Estoy usando Administrador. Ejecute la siguiente consulta contra el sitepoint base de datos, asegurándose de que su usuario tenga derechos de administrador en el servidor MySQL:

DELIMITER $$ CREATE PROCEDURE `sp_get_authors`()
BEGIN SELECT id, name, city FROM authors;
END $$

Esto creará y almacenará el procedimiento en el information_schema base de datos en el ROUTINES mesa.

Creando procedimiento almacenado en Adminer

Nota: si la sintaxis del delimitador le parece extraña, se explica esta página.

A continuación, establezca una conexión y utilice el objeto de conexión para llamar al procedimiento almacenado como se muestra:

con.query('CALL sp_get_authors()',function(err, rows){ if (err) throw err; console.log('Data received from Db:'); console.log(rows);
});

Guarde los cambios y ejecute el archivo. Una vez que se ejecuta, debería poder ver los datos devueltos desde la base de datos:

[ [ 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 } ]

Junto con los datos, devuelve información adicional, como el número de filas afectadas, insertId etc. Debe iterar sobre el índice 0 de los datos devueltos para separar los detalles de los empleados del resto de la información:

rows[0].forEach( (row) => { console.log(`${row.name} lives in ${row.city}`);
});

Esto le da lo siguiente:

Michaela Lehr lives in Berlin
Michael Wanyoike lives in Nairobi
James Hibbard lives in Leipzig
Karolina Gawron lives in Wrocław

Ahora consideremos un procedimiento almacenado que requiere un parámetro de entrada:

DELIMITER $$ CREATE PROCEDURE `sp_get_author_details`( in author_id int
)
BEGIN SELECT name, city FROM authors where id = author_id;
END $$

Podemos pasar el parámetro de entrada mientras hacemos una llamada al procedimiento almacenado:

con.query('CALL sp_get_author_details(1)', (err, rows) => { if(err) throw err; console.log('Data received from Db:n'); console.log(rows[0]);
});

Esto le da lo siguiente:

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

La mayoría de las veces, cuando intentamos insertar un registro en la base de datos, necesitamos que se devuelva la última ID insertada como parámetro de salida. Considere el siguiente procedimiento almacenado de inserción con un parámetro de salida:

DELIMITER $$ CREATE PROCEDURE `sp_insert_author`( out author_id int, in author_name varchar(25), in author_city varchar(25)
)
BEGIN insert into authors(name, city) values(author_name, author_city); set author_id = LAST_INSERT_ID();
END $$

Para realizar una llamada a procedimiento con un parámetro out, primero necesitamos habilitar múltiples llamadas mientras creamos la conexión. Por lo tanto, modifique la conexión estableciendo la ejecución de múltiples instrucciones en true:

const con = mysql.createConnection({ host: 'localhost', user: 'user', password: 'password', database: 'sitepoint', multipleStatements: true
});

A continuación, al realizar una llamada al procedimiento, establezca un parámetro de salida y páselo:

con.query( "SET @author_id = 0; CALL sp_insert_author(@author_id, 'Craig Buckler', 'Exmouth'); SELECT @author_id", (err, rows) => { if (err) throw err; console.log('Data received from Db:n'); console.log(rows); }
);

Como se ve en el código anterior, hemos establecido un @author_id out y lo pasó mientras realizaba una llamada al procedimiento almacenado. Una vez realizada la llamada, debemos seleccionar el parámetro out para acceder a la ID devuelta.

Ejecutar app.js. En una ejecución exitosa, debería poder ver el parámetro seleccionado junto con otra información. rows[2] debería darle acceso al parámetro de salida seleccionado:

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

Nota: Para eliminar un procedimiento almacenado, debe ejecutar el comando DROP PROCEDURE <procedure-name>; contra la base de datos para la que lo creó.

Escapar la entrada del usuario

Para evitar ataques de inyección SQL, debe hacerlo escapar de cualquier dato que reciba de los usuarios antes de usarlo dentro de una consulta SQL. Demostremos por qué:

const userSubmittedVariable = '1'; con.query( `SELECT * FROM authors WHERE id = ${userSubmittedVariable}`, (err, rows) => { if(err) throw err; console.log(rows); }
);

Esto parece bastante inofensivo e incluso devuelve el resultado correcto:

 { id: 1, name: 'Michaela Lehr', city: 'Berlin' }

Sin embargo, intente cambiar el userSubmittedVariable a esto:

const userSubmittedVariable = '1 OR 1=1';

De repente, tenemos acceso a todo el conjunto de datos. Ahora cámbielo a esto:

const userSubmittedVariable = '1; DROP TABLE authors';

¡Ahora estamos en problemas!

La buena noticia es que hay ayuda disponible. Solo tienes que usar el mysql.escape método:

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

También puede utilizar un marcador de posición de signo de interrogación, como hicimos en los ejemplos al principio del artículo:

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

¿Por qué no usar simplemente un ORM?

Antes de entrar en los pros y los contras de este enfoque, tomemos un segundo para ver qué son los ORM. Lo siguiente está tomado de una respuesta en Stack Overflow:

El mapeo relacional de objetos (ORM) es una técnica que le permite consultar y manipular datos de una base de datos utilizando un paradigma orientado a objetos. Cuando se habla de ORM, la mayoría de la gente se refiere a una biblioteca que implementa la técnica de mapeo relacional de objetos, de ahí la frase "un ORM".

Entonces, esto significa que escribe la lógica de su base de datos en el lenguaje específico del dominio del ORM, a diferencia del enfoque básico que hemos estado adoptando hasta ahora. Para darle una idea de cómo podría verse esto, aquí hay un ejemplo usando Secuela, que consulta la base de datos de todos los autores y los registra en la consola:

const sequelize = new Sequelize('sitepoint', 'user', 'password', { host: 'localhost', dialect: 'mysql'
}); const Author = sequelize.define('author', { name: { type: Sequelize.STRING, }, city: { type: Sequelize.STRING },
}, { timestamps: false
}); Author.findAll().then(authors => { console.log("All authors:", JSON.stringify(authors, null, 4));
});

Si el uso de un ORM tiene sentido para usted o no, dependerá en gran medida de en qué esté trabajando y con quién. Por un lado, los ORMS tienden a hacer que los desarrolladores sean más productivos, en parte abstrayendo una gran parte del SQL para que no todos en el equipo necesiten saber cómo escribir consultas específicas de bases de datos súper eficientes. También es fácil pasar a un software de base de datos diferente, porque está desarrollando una abstracción.

Sin embargo, por otro lado, es posible escribir un SQL realmente desordenado e ineficiente como resultado de no entender cómo el ORM hace lo que hace. El rendimiento también es un problema, ya que es mucho más fácil optimizar las consultas que no tienen que pasar por el ORM.

Cualquiera que sea el camino que tome depende de usted, pero si esta es una decisión que está en proceso de tomar, consulte este hilo de Stack Overflow: ¿Por qué debería utilizar un ORM?. Consulte también esta publicación en SitePoint: 3 ORM de JavaScript que quizás no conozca.

Conclusión

En este tutorial, hemos instalado el cliente mysql para Node.js y lo configuró para conectarse a una base de datos. También hemos visto cómo realizar operaciones CRUD, trabajar con declaraciones preparadas y escapar de la entrada del usuario para mitigar los ataques de inyección SQL. Y, sin embargo, solo hemos arañado la superficie de lo que ofrece el cliente mysql. Para obtener información más detallada, recomiendo leer el documentación oficial.

Y tenga en cuenta que el módulo mysql no es el único programa en la ciudad. También hay otras opciones, como la popular nodo-mysql2.

Fuente: https://www.sitepoint.com/using-node-mysql-javascript-client/?utm_source=rss

punto_img

Información más reciente

punto_img