Conectar Node.js con MySQL
Node.js se ha convertido en una de las plataformas más populares para construir aplicaciones del lado del servidor, y MySQL sigue siendo una de las bases de datos relacionales más utilizadas en el mundo. Combinar ambas tecnologías te permite crear aplicaciones web robustas y eficientes. En este artículo aprenderás a establecer una conexión entre Node.js y MySQL utilizando el paquete mysql2, que es la opción recomendada por su soporte nativo de promesas y sentencias preparadas.
Requisitos previos
Para seguir este tutorial necesitas tener instalado Node.js en su versión 14 o superior y un servidor MySQL en ejecución. Puedes verificar tu versión de Node.js ejecutando node --version en la terminal. También necesitas acceso a un usuario de MySQL con permisos para crear bases de datos y tablas.
Instalación
El primer paso es crear un proyecto de Node.js e instalar el paquete mysql2. Abre tu terminal y ejecuta los siguientes comandos:
// Inicializar el proyecto
// npm init -y
// Instalar mysql2
// npm install mysql2El paquete mysql2 es una reimplementación moderna del antiguo paquete mysql para Node.js. Ofrece mejor rendimiento, soporte para sentencias preparadas del lado del servidor y una API compatible con promesas.
Código completo
A continuación se muestra un ejemplo completo que establece una conexión con MySQL, ejecuta una consulta de prueba y cierra la conexión:
const mysql = require('mysql2/promise');
async function conectar() {
// Crear la conexión
const connection = await mysql.createConnection({
host: 'localhost',
user: 'root',
password: 'tu_contraseña',
database: 'tienda'
});
// Probar la conexión
const [rows] = await connection.execute('SELECT 1 + 1 AS resultado');
console.log('Conexión exitosa. Resultado:', rows[0].resultado);
// Cerrar la conexión
await connection.end();
}
conectar().catch(console.error);Salida esperada:
Conexión exitosa. Resultado: 2
Explicación paso a paso
El proceso de conexión comienza importando el módulo mysql2/promise, que proporciona una API basada en promesas en lugar de callbacks. Esto permite utilizar la sintaxis async/await que hace el código más legible y fácil de mantener.
La función createConnection() acepta un objeto de configuración con las siguientes opciones principales:
const opciones = {
host: 'localhost', // Dirección del servidor MySQL
port: 3306, // Puerto (3306 por defecto)
user: 'root', // Usuario de MySQL
password: 'tu_contraseña', // Contraseña del usuario
database: 'tienda', // Base de datos a usar
charset: 'utf8mb4', // Juego de caracteres (recomendado utf8mb4)
timezone: '+00:00', // Zona horaria
connectTimeout: 10000, // Timeout de conexión en milisegundos
waitForConnections: true, // Esperar si no hay conexiones disponibles
decimalNumbers: true // Devolver DECIMAL como números en lugar de strings
};Sin embargo, para aplicaciones en producción se recomienda usar un pool de conexiones en lugar de una conexión individual. Un pool mantiene varias conexiones abiertas y las reutiliza, lo que mejora significativamente el rendimiento cuando múltiples solicitudes necesitan acceder a la base de datos de forma concurrente.
Crear un pool de conexiones
const mysql = require('mysql2/promise');
// Crear el pool (se recomienda crearlo una sola vez al iniciar la aplicación)
const pool = mysql.createPool({
host: 'localhost',
user: 'root',
password: 'tu_contraseña',
database: 'tienda',
waitForConnections: true,
connectionLimit: 10, // Máximo de conexiones simultáneas
maxIdle: 10, // Máximo de conexiones inactivas
idleTimeout: 60000, // Tiempo antes de cerrar conexión inactiva (ms)
queueLimit: 0, // Límite de la cola de espera (0 = ilimitado)
enableKeepAlive: true, // Mantener conexiones vivas
keepAliveInitialDelay: 0 // Delay inicial del keep-alive
});
async function consultarProductos() {
// El pool gestiona automáticamente obtener y devolver conexiones
const [rows] = await pool.execute('SELECT * FROM productos LIMIT 5');
console.log('Productos encontrados:', rows.length);
rows.forEach(producto => {
console.log(`- ${producto.nombre}: $${producto.precio}`);
});
}
consultarProductos().catch(console.error);Salida esperada:
Productos encontrados: 5
- Laptop HP Pavilion: $12999.99
- Mouse Logitech MX Master: $1599.00
- Teclado Mecánico Corsair: $2299.50
- Monitor Samsung 27": $6499.00
- Auriculares Sony WH-1000XM5: $5999.99
La diferencia fundamental entre createConnection() y createPool() es que el pool administra un conjunto de conexiones automáticamente. Cuando ejecutas una consulta a través del pool, este obtiene una conexión disponible, ejecuta la consulta y devuelve la conexión al pool para su reutilización. Esto elimina la sobrecarga de abrir y cerrar conexiones constantemente.
Obtener una conexión del pool
En algunos casos necesitas ejecutar varias consultas usando la misma conexión, por ejemplo cuando trabajas con transacciones. Para esto puedes obtener una conexión específica del pool:
async function transaccionEjemplo() {
const connection = await pool.getConnection();
try {
await connection.beginTransaction();
await connection.execute(
'UPDATE cuentas SET saldo = saldo - ? WHERE id = ?',
[500.00, 1]
);
await connection.execute(
'UPDATE cuentas SET saldo = saldo + ? WHERE id = ?',
[500.00, 2]
);
await connection.commit();
console.log('Transacción completada exitosamente');
} catch (error) {
await connection.rollback();
console.error('Error en la transacción:', error.message);
} finally {
connection.release(); // Siempre devolver la conexión al pool
}
}Es fundamental llamar a connection.release() en el bloque finally para devolver la conexión al pool. Si olvidas liberar la conexión, el pool se quedará sin conexiones disponibles y tu aplicación dejará de funcionar.
Caso práctico
Veamos un ejemplo realista de cómo estructurar la conexión en una aplicación Express:
// archivo: db.js
const mysql = require('mysql2/promise');
const pool = mysql.createPool({
host: process.env.DB_HOST || 'localhost',
user: process.env.DB_USER || 'root',
password: process.env.DB_PASSWORD || '',
database: process.env.DB_NAME || 'tienda',
connectionLimit: 10,
charset: 'utf8mb4'
});
// Verificar la conexión al iniciar
pool.getConnection()
.then(conn => {
console.log('Conectado a MySQL como ID', conn.threadId);
conn.release();
})
.catch(err => {
console.error('Error al conectar con MySQL:', err.message);
process.exit(1);
});
module.exports = pool;// archivo: app.js
const express = require('express');
const pool = require('./db');
const app = express();
app.get('/productos', async (req, res) => {
try {
const [productos] = await pool.execute('SELECT * FROM productos');
res.json(productos);
} catch (error) {
res.status(500).json({ error: 'Error al consultar productos' });
}
});
app.listen(3000, () => console.log('Servidor en puerto 3000'));Este patrón de exportar el pool desde un módulo centralizado es una práctica recomendada porque garantiza que toda la aplicación comparta el mismo pool de conexiones.
Manejo de errores
La conexión a MySQL puede fallar por múltiples razones. Es importante manejar cada tipo de error de forma apropiada:
const mysql = require('mysql2/promise');
async function conectarConManejo() {
try {
const connection = await mysql.createConnection({
host: 'localhost',
user: 'root',
password: 'contraseña_incorrecta',
database: 'base_inexistente'
});
await connection.end();
} catch (error) {
switch (error.code) {
case 'ER_ACCESS_DENIED_ERROR':
console.error('Credenciales incorrectas. Verifica usuario y contraseña.');
break;
case 'ER_BAD_DB_ERROR':
console.error('La base de datos especificada no existe.');
break;
case 'ECONNREFUSED':
console.error('No se pudo conectar al servidor MySQL. ¿Está en ejecución?');
break;
case 'ENOTFOUND':
console.error('No se encontró el host especificado.');
break;
case 'ETIMEDOUT':
console.error('La conexión tardó demasiado. Verifica la red.');
break;
default:
console.error('Error inesperado:', error.code, error.message);
}
}
}
conectarConManejo();El pool también emite eventos que puedes escuchar para monitorear el estado de las conexiones:
pool.on('connection', (connection) => {
console.log('Nueva conexión establecida:', connection.threadId);
});
pool.on('release', (connection) => {
console.log('Conexión liberada:', connection.threadId);
});
pool.on('enqueue', () => {
console.log('Esperando conexión disponible en el pool...');
});Ahora que sabes cómo establecer la conexión entre Node.js y MySQL, en el siguiente artículo aprenderás a ejecutar consultas SELECT para recuperar datos de tus tablas.
Escrito por Eduardo Lázaro
