Node.js with MySQL
Node.js is an open-source, cross-platform, back-end JavaScript runtime that runs code outside a browser. Building scalable network applications with it is usual. Node.js applications utilise a client library or “driver” to connect to MySQL databases and run SQL queries.
How Node.js Interacts with MySQL
Node.js uses database drivers like mysql or mysql2 to interact with MySQL. JavaScript code can connect to a MySQL server, send SQL commands, and process results using these drivers’ API.
General steps:
- Installation of the MySQL Driver: Use npm to install an appropriate MySQL client library in Node.js. As an example: npm install mysql
- Establishing a Connection: After installation, the program imports the library and connects to MySQL. Server host, user, password, and database name are usually needed.
- Executing Queries: After a successful connection, the program can perform SQL queries (SELECT, INSERT, UPDATE, DELETE) via driver methods. Asynchronous operations are supported by callbacks or Promises in these methods.
- Handling Results and Errors: The driver returns SELECT query results (rows of data) and handles process faults.
- Closing the Connection: To free up resources, close the database connection when no longer needed. Web applications commonly utilise connection pooling to efficiently handle connections without opening and terminating them for each request.
Node.js Syntax for MySQL
To use MySQL with Node.js, you’d first need to install a MySQL client library (e.g., mysql2).
npm install mysql2
Here are basic examples of common MySQL operations using Node.js:
Connecting to MySQL
const mysql = require('mysql2'); // Import the mysql2 package
// Create a connection pool (recommended for performance)
const pool = mysql.createPool({
host: 'localhost',
user: 'your_username',
password: 'your_password',
database: 'your_database'
});
// Get a promise-based connection for async/await
const promisePool = pool.promise();
async function testConnection() {
try {
const [rows, fields] = await promisePool.query('SELECT 1 + 1 AS solution');
console.log('The solution is: ', rows.solution); // Expected output: 2
console.log('Successfully connected to MySQL!');
} catch (err) {
console.error('Error connecting to MySQL: ', err);
} finally {
// In a real application, keep the pool open or close it gracefully on shutdown.
// For this example, we won't close the pool immediately after the test.
}
}
testConnection();
Creating a Table
async function createTable() {
const createTableSQL = `
CREATE TABLE IF NOT EXISTS Products (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(100) NOT NULL,
price DECIMAL(10, 2),
stock INT
)
`;
try {
const [result] = await promisePool.query(createTableSQL);
console.log("Table 'Products' created successfully or already exists.");
} catch (err) {
console.error("Error creating table: ", err);
}
}
createTable();
Inserting Data
async function insertData() {
const insertSQL = "INSERT INTO Products (name, price, stock) VALUES (?, ?, ?)";
try {
// Insert a single record
const [result1] = await promisePool.execute(insertSQL, ['Laptop', 1200.50, 10]);
console.log(`Inserted Laptop: ${result1.affectedRows} row(s) affected.`);
// Insert multiple records using an array of arrays
const products = [
['Mouse', 25.00, 50],
['Keyboard', 75.20, 30]
];
for (const product of products) {
const [result] = await promisePool.execute(insertSQL, product);
console.log(`Inserted ${product}: ${result.affectedRows} row(s) affected.`);
}
} catch (err) {
console.error("Error inserting data: ", err);
}
}
insertData();
Retrieving Data
async function retrieveData() {
try {
// Select all records
const [rowsAll] = await promisePool.query("SELECT * FROM Products");
console.log("\n--- All Products ---");
rowsAll.forEach(product => console.log(product));
// Select specific records with a WHERE clause
const [rowsFiltered] = await promisePool.execute("SELECT name, price FROM Products WHERE price > ?", [24]);
console.log("\n--- Products with Price > 100 ---");
rowsFiltered.forEach(product => console.log(product));
} catch (err) {
console.error("Error retrieving data: ", err);
}
}
retrieveData();
Updating Data
async function updateData() {
const updateSQL = "UPDATE Products SET price = ? WHERE name = ?";
try {
const [result] = await promisePool.execute(updateSQL, [1250.00, 'Laptop']);
console.log(`Updated Laptop: ${result.affectedRows} row(s) affected.`);
} catch (err) {
console.error("Error updating data: ", err);
}
}
updateData();
Deleting Data
async function deleteData() {
const deleteSQL = "DELETE FROM Products WHERE name = ?";
try {
const [result] = await promisePool.execute(deleteSQL, ['Mouse']);
console.log(`Deleted Mouse: ${result.affectedRows} row(s) affected.`);
} catch (err) {
console.error("Error deleting data: ", err);
}
}
deleteData();
Important Considerations
Parameterized Queries: Using placeholders (e.g., ? in the Node.js mysql2 examples) for values in SQL queries is a crucial best practice to prevent SQL injection vulnerabilities. This protects against malicious input by treating values as data rather than executable code.
Error Handling: It is essential to implement robust error handling using try-catch blocks to manage potential database connection issues or query failures.
Connection Management: For applications handling multiple requests, using a connection pool (as shown in the Node.js example) is more efficient than opening and closing a new connection for every query.
Asynchronous Nature: Node.js operates asynchronously, meaning database operations (like query or execute) return Promises or use callbacks, allowing your application to remain non-blocking.