|
|
马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?立即注册
x
引言
Node.js作为当今流行的后端JavaScript运行环境,与MySQL这一广泛应用的关系型数据库相结合,为全栈开发提供了强大而灵活的解决方案。本指南将带你从零开始,逐步掌握Node.js与MySQL的连接技术,从基础的环境配置到复杂的数据库操作,帮助你构建高效、安全的数据驱动应用。
一、环境配置
1. Node.js安装与配置
首先,确保你的系统已安装Node.js。如果尚未安装,请访问Node.js官网下载并安装最新的LTS版本。
安装完成后,在终端中运行以下命令验证安装:
你将看到类似以下的输出,显示安装的Node.js和npm版本:
2. MySQL安装与配置
1. 访问MySQL官网下载MySQL Installer
2. 运行安装程序,选择”Full”安装类型以包含所有组件
3. 在配置过程中,设置root用户密码并记住它
4. 完成安装后,确保MySQL服务已启动
使用Homebrew安装MySQL:
- brew update
- brew install mysql
复制代码
安装完成后,启动MySQL服务:
- brew services start mysql
复制代码
对于Ubuntu/Debian系统:
- sudo apt update
- sudo apt install mysql-server
- sudo mysql_secure_installation
复制代码
对于CentOS/RHEL系统:
- sudo yum update
- sudo yum install mysql-server
- sudo systemctl start mysqld
- sudo systemctl enable mysqld
复制代码
在终端中运行以下命令登录MySQL:
输入你设置的root密码,成功登录后将看到MySQL命令行提示符:
二、连接建立
1. 创建Node.js项目
首先,创建一个新的项目目录并初始化npm项目:
- mkdir node-mysql-guide
- cd node-mysql-guide
- npm init -y
复制代码
2. 安装MySQL驱动
Node.js有多种MySQL驱动可供选择,最常用的是mysql和mysql2。mysql2是mysql的增强版,提供了更好的性能和Promise支持。
3. 基本连接示例
创建一个名为app.js的文件,添加以下代码:
- const mysql = require('mysql2');
- // 创建连接配置
- const connection = mysql.createConnection({
- host: 'localhost',
- user: 'root',
- password: 'your_password', // 替换为你的MySQL密码
- database: 'my_database' // 可选,指定要连接的数据库
- });
- // 连接到MySQL
- connection.connect(error => {
- if (error) {
- console.error('Error connecting to the database: ' + error.stack);
- return;
- }
- console.log('Connected to MySQL with id ' + connection.threadId);
-
- // 在这里执行数据库操作
-
- // 关闭连接
- connection.end();
- });
复制代码
运行这个文件:
如果一切正常,你将看到连接成功的消息。
4. 使用连接池
在生产环境中,推荐使用连接池来管理数据库连接,以提高性能和资源利用率。
- const mysql = require('mysql2');
- // 创建连接池
- const pool = mysql.createPool({
- host: 'localhost',
- user: 'root',
- password: 'your_password',
- database: 'my_database',
- waitForConnections: true,
- connectionLimit: 10, // 连接池大小
- queueLimit: 0
- });
- // 将连接池转换为Promise支持
- const promisePool = pool.promise();
- // 使用连接池查询数据库
- async function queryDatabase() {
- try {
- const [rows, fields] = await promisePool.query('SELECT * FROM users');
- console.log(rows);
- } catch (error) {
- console.error('Error querying database:', error);
- }
- }
- queryDatabase();
复制代码
5. 使用环境变量管理敏感信息
在实际项目中,不应将数据库凭据硬编码在代码中。使用dotenv包从环境变量加载配置:
在项目根目录创建.env文件:
- DB_HOST=localhost
- DB_USER=root
- DB_PASSWORD=your_password
- DB_DATABASE=my_database
复制代码
修改连接代码:
- require('dotenv').config();
- const mysql = require('mysql2');
- const pool = mysql.createPool({
- host: process.env.DB_HOST,
- user: process.env.DB_USER,
- password: process.env.DB_PASSWORD,
- database: process.env.DB_DATABASE,
- waitForConnections: true,
- connectionLimit: 10,
- queueLimit: 0
- });
- const promisePool = pool.promise();
- module.exports = promisePool;
复制代码
三、数据库操作
1. 创建数据库和表
首先,让我们创建一个示例数据库和表:
- const promisePool = require('./db'); // 假设上面的连接池代码保存在db.js中
- async function setupDatabase() {
- try {
- // 创建数据库(如果不存在)
- await promisePool.query('CREATE DATABASE IF NOT EXISTS my_app_db');
- console.log('Database created or already exists');
-
- // 使用数据库
- await promisePool.query('USE my_app_db');
-
- // 创建用户表
- const createUsersTable = `
- CREATE TABLE IF NOT EXISTS users (
- id INT AUTO_INCREMENT PRIMARY KEY,
- name VARCHAR(255) NOT NULL,
- email VARCHAR(255) NOT NULL UNIQUE,
- created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
- )
- `;
- await promisePool.query(createUsersTable);
- console.log('Users table created or already exists');
-
- // 创建产品表
- const createProductsTable = `
- CREATE TABLE IF NOT EXISTS products (
- id INT AUTO_INCREMENT PRIMARY KEY,
- name VARCHAR(255) NOT NULL,
- price DECIMAL(10, 2) NOT NULL,
- stock_quantity INT NOT NULL DEFAULT 0,
- created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
- )
- `;
- await promisePool.query(createProductsTable);
- console.log('Products table created or already exists');
-
- // 创建订单表
- const createOrdersTable = `
- CREATE TABLE IF NOT EXISTS orders (
- id INT AUTO_INCREMENT PRIMARY KEY,
- user_id INT NOT NULL,
- total_amount DECIMAL(10, 2) NOT NULL,
- order_date TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
- FOREIGN KEY (user_id) REFERENCES users(id)
- )
- `;
- await promisePool.query(createOrdersTable);
- console.log('Orders table created or already exists');
-
- } catch (error) {
- console.error('Error setting up database:', error);
- }
- }
- setupDatabase();
复制代码
2. 插入数据(Create)
- async function insertUser(name, email) {
- try {
- const sql = 'INSERT INTO users (name, email) VALUES (?, ?)';
- const [result] = await promisePool.query(sql, [name, email]);
- console.log('User inserted with ID:', result.insertId);
- return result.insertId;
- } catch (error) {
- console.error('Error inserting user:', error);
- throw error;
- }
- }
- // 使用示例
- insertUser('John Doe', 'john@example.com')
- .then(id => console.log('New user ID:', id))
- .catch(error => console.error('Failed to insert user:', error));
复制代码- async function insertMultipleUsers(users) {
- try {
- const sql = 'INSERT INTO users (name, email) VALUES ?';
- const values = users.map(user => [user.name, user.email]);
- const [result] = await promisePool.query(sql, [values]);
- console.log(`${result.affectedRows} users inserted`);
- return result.affectedRows;
- } catch (error) {
- console.error('Error inserting multiple users:', error);
- throw error;
- }
- }
- // 使用示例
- const newUsers = [
- { name: 'Alice Johnson', email: 'alice@example.com' },
- { name: 'Bob Smith', email: 'bob@example.com' },
- { name: 'Charlie Brown', email: 'charlie@example.com' }
- ];
- insertMultipleUsers(newUsers)
- .then(count => console.log(`${count} users inserted`))
- .catch(error => console.error('Failed to insert users:', error));
复制代码
3. 查询数据(Read)
- async function getAllUsers() {
- try {
- const [rows] = await promisePool.query('SELECT * FROM users');
- return rows;
- } catch (error) {
- console.error('Error fetching users:', error);
- throw error;
- }
- }
- // 使用示例
- getAllUsers()
- .then(users => console.log('All users:', users))
- .catch(error => console.error('Failed to fetch users:', error));
复制代码- async function getUserById(id) {
- try {
- const [rows] = await promisePool.query('SELECT * FROM users WHERE id = ?', [id]);
- if (rows.length > 0) {
- return rows[0];
- }
- return null; // 用户不存在
- } catch (error) {
- console.error('Error fetching user by ID:', error);
- throw error;
- }
- }
- // 使用示例
- getUserById(1)
- .then(user => {
- if (user) {
- console.log('Found user:', user);
- } else {
- console.log('User not found');
- }
- })
- .catch(error => console.error('Failed to fetch user:', error));
复制代码- async function searchUsersByName(searchTerm) {
- try {
- const [rows] = await promisePool.query(
- 'SELECT * FROM users WHERE name LIKE ?',
- [`%${searchTerm}%`]
- );
- return rows;
- } catch (error) {
- console.error('Error searching users by name:', error);
- throw error;
- }
- }
- // 使用示例
- searchUsersByName('John')
- .then(users => console.log('Users matching "John":', users))
- .catch(error => console.error('Failed to search users:', error));
复制代码- async function getUsersPaginated(page = 1, pageSize = 10) {
- try {
- const offset = (page - 1) * pageSize;
- const [rows] = await promisePool.query(
- 'SELECT * FROM users LIMIT ? OFFSET ?',
- [pageSize, offset]
- );
-
- // 获取总记录数
- const [countResult] = await promisePool.query('SELECT COUNT(*) as total FROM users');
- const total = countResult[0].total;
-
- return {
- data: rows,
- pagination: {
- page,
- pageSize,
- total,
- totalPages: Math.ceil(total / pageSize)
- }
- };
- } catch (error) {
- console.error('Error fetching paginated users:', error);
- throw error;
- }
- }
- // 使用示例
- getUsersPaginated(1, 5)
- .then(result => {
- console.log('Page data:', result.data);
- console.log('Pagination info:', result.pagination);
- })
- .catch(error => console.error('Failed to fetch paginated users:', error));
复制代码
4. 更新数据(Update)
- async function updateUserEmail(id, newEmail) {
- try {
- const [result] = await promisePool.query(
- 'UPDATE users SET email = ? WHERE id = ?',
- [newEmail, id]
- );
-
- if (result.affectedRows === 0) {
- return false; // 用户不存在
- }
-
- console.log('User email updated');
- return true;
- } catch (error) {
- console.error('Error updating user email:', error);
- throw error;
- }
- }
- // 使用示例
- updateUserEmail(1, 'new.email@example.com')
- .then(success => {
- if (success) {
- console.log('Email updated successfully');
- } else {
- console.log('User not found');
- }
- })
- .catch(error => console.error('Failed to update email:', error));
复制代码- async function updateMultipleUsers(updates) {
- try {
- // 使用CASE语句进行批量更新
- let sql = 'UPDATE users SET email = CASE id ';
- const ids = [];
- const emails = [];
-
- updates.forEach(update => {
- sql += 'WHEN ? THEN ? ';
- ids.push(update.id);
- emails.push(update.email);
- });
-
- sql += 'END WHERE id IN (';
- sql += ids.map(() => '?').join(',');
- sql += ')';
-
- const params = [...ids, ...emails, ...ids];
- const [result] = await promisePool.query(sql, params);
-
- console.log(`${result.affectedRows} users updated`);
- return result.affectedRows;
- } catch (error) {
- console.error('Error updating multiple users:', error);
- throw error;
- }
- }
- // 使用示例
- const updates = [
- { id: 1, email: 'updated1@example.com' },
- { id: 2, email: 'updated2@example.com' },
- { id: 3, email: 'updated3@example.com' }
- ];
- updateMultipleUsers(updates)
- .then(count => console.log(`${count} users updated`))
- .catch(error => console.error('Failed to update users:', error));
复制代码
5. 删除数据(Delete)
- async function deleteUser(id) {
- try {
- const [result] = await promisePool.query('DELETE FROM users WHERE id = ?', [id]);
-
- if (result.affectedRows === 0) {
- return false; // 用户不存在
- }
-
- console.log('User deleted');
- return true;
- } catch (error) {
- console.error('Error deleting user:', error);
- throw error;
- }
- }
- // 使用示例
- deleteUser(1)
- .then(success => {
- if (success) {
- console.log('User deleted successfully');
- } else {
- console.log('User not found');
- }
- })
- .catch(error => console.error('Failed to delete user:', error));
复制代码- async function deleteMultipleUsers(ids) {
- try {
- const [result] = await promisePool.query(
- 'DELETE FROM users WHERE id IN (?)',
- [ids]
- );
-
- console.log(`${result.affectedRows} users deleted`);
- return result.affectedRows;
- } catch (error) {
- console.error('Error deleting multiple users:', error);
- throw error;
- }
- }
- // 使用示例
- deleteMultipleUsers([2, 3, 4])
- .then(count => console.log(`${count} users deleted`))
- .catch(error => console.error('Failed to delete users:', error));
复制代码
四、高级操作
1. 事务处理
事务是一组SQL语句的集合,这些语句要么全部执行成功,要么全部失败回滚。在处理需要多个步骤的操作时,事务非常重要。
- async function placeOrder(userId, productIds) {
- const connection = await promisePool.getConnection();
-
- try {
- // 开始事务
- await connection.beginTransaction();
-
- // 获取用户信息
- const [users] = await connection.query('SELECT * FROM users WHERE id = ?', [userId]);
- if (users.length === 0) {
- throw new Error('User not found');
- }
-
- // 计算订单总额
- let totalAmount = 0;
- for (const productId of productIds) {
- const [products] = await connection.query('SELECT * FROM products WHERE id = ?', [productId]);
- if (products.length === 0) {
- throw new Error(`Product with ID ${productId} not found`);
- }
- totalAmount += parseFloat(products[0].price);
- }
-
- // 创建订单
- const [orderResult] = await connection.query(
- 'INSERT INTO orders (user_id, total_amount) VALUES (?, ?)',
- [userId, totalAmount]
- );
- const orderId = orderResult.insertId;
-
- // 更新产品库存
- for (const productId of productIds) {
- await connection.query(
- 'UPDATE products SET stock_quantity = stock_quantity - 1 WHERE id = ?',
- [productId]
- );
- }
-
- // 提交事务
- await connection.commit();
- console.log('Order placed successfully');
- return orderId;
-
- } catch (error) {
- // 发生错误,回滚事务
- await connection.rollback();
- console.error('Error placing order:', error);
- throw error;
- } finally {
- // 释放连接回连接池
- connection.release();
- }
- }
- // 使用示例
- placeOrder(1, [1, 2, 3])
- .then(orderId => console.log('Order placed with ID:', orderId))
- .catch(error => console.error('Failed to place order:', error));
复制代码
2. 预处理语句防止SQL注入
SQL注入是一种常见的网络安全漏洞,通过使用预处理语句(参数化查询),可以有效防止SQL注入攻击。
- async function safeUserLogin(email, password) {
- try {
- // 使用预处理语句防止SQL注入
- const [rows] = await promisePool.query(
- 'SELECT * FROM users WHERE email = ? AND password = ?',
- [email, password]
- );
-
- if (rows.length > 0) {
- // 不返回密码等敏感信息
- const { password, ...userWithoutPassword } = rows[0];
- return userWithoutPassword;
- }
-
- return null; // 认证失败
- } catch (error) {
- console.error('Error during user login:', error);
- throw error;
- }
- }
- // 使用示例
- safeUserLogin('user@example.com', 'securepassword123')
- .then(user => {
- if (user) {
- console.log('Login successful. User:', user);
- } else {
- console.log('Login failed. Invalid email or password.');
- }
- })
- .catch(error => console.error('Login error:', error));
复制代码
3. 异步操作处理
Node.js的异步特性使得处理数据库操作时需要特别注意。以下是使用async/await处理异步操作的示例:
- class UserService {
- constructor(dbPool) {
- this.dbPool = dbPool;
- }
-
- async createUser(userData) {
- try {
- const { name, email } = userData;
- const [result] = await this.dbPool.query(
- 'INSERT INTO users (name, email) VALUES (?, ?)',
- [name, email]
- );
-
- // 获取新创建的用户
- const [newUser] = await this.dbPool.query(
- 'SELECT * FROM users WHERE id = ?',
- [result.insertId]
- );
-
- return newUser[0];
- } catch (error) {
- if (error.code === 'ER_DUP_ENTRY') {
- throw new Error('Email already exists');
- }
- console.error('Error creating user:', error);
- throw error;
- }
- }
-
- async getUserWithOrders(userId) {
- try {
- // 并行执行多个查询
- const [userResult, ordersResult] = await Promise.all([
- this.dbPool.query('SELECT * FROM users WHERE id = ?', [userId]),
- this.dbPool.query('SELECT * FROM orders WHERE user_id = ?', [userId])
- ]);
-
- const user = userResult[0][0];
- const orders = ordersResult[0];
-
- if (!user) {
- return null;
- }
-
- // 返回用户及其订单
- return {
- ...user,
- orders
- };
- } catch (error) {
- console.error('Error fetching user with orders:', error);
- throw error;
- }
- }
- }
- // 使用示例
- const userService = new UserService(promisePool);
- // 创建用户
- userService.createUser({ name: 'Jane Doe', email: 'jane@example.com' })
- .then(user => {
- console.log('Created user:', user);
- // 获取用户及其订单
- return userService.getUserWithOrders(user.id);
- })
- .then(userWithOrders => {
- if (userWithOrders) {
- console.log('User with orders:', userWithOrders);
- } else {
- console.log('User not found');
- }
- })
- .catch(error => console.error('Error:', error));
复制代码
五、实战案例:构建一个简单的RESTful API
让我们使用Express框架和MySQL构建一个简单的用户管理API。
1. 安装必要的依赖
- npm install express body-parser cors
复制代码
2. 创建API服务器
创建一个名为server.js的文件:
- require('dotenv').config();
- const express = require('express');
- const bodyParser = require('body-parser');
- const cors = require('cors');
- const mysql = require('mysql2');
- const app = express();
- const PORT = process.env.PORT || 3000;
- // 中间件
- app.use(bodyParser.json());
- app.use(cors());
- // MySQL连接池
- const pool = mysql.createPool({
- host: process.env.DB_HOST,
- user: process.env.DB_USER,
- password: process.env.DB_PASSWORD,
- database: process.env.DB_DATABASE,
- waitForConnections: true,
- connectionLimit: 10,
- queueLimit: 0
- });
- const promisePool = pool.promise();
- // 确保数据库和表存在
- async function initializeDatabase() {
- try {
- await promisePool.query('CREATE DATABASE IF NOT EXISTS my_app_db');
- await promisePool.query('USE my_app_db');
-
- const createUsersTable = `
- CREATE TABLE IF NOT EXISTS users (
- id INT AUTO_INCREMENT PRIMARY KEY,
- name VARCHAR(255) NOT NULL,
- email VARCHAR(255) NOT NULL UNIQUE,
- created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
- )
- `;
- await promisePool.query(createUsersTable);
- console.log('Database initialized');
- } catch (error) {
- console.error('Error initializing database:', error);
- }
- }
- // API路由
- // 获取所有用户
- app.get('/api/users', async (req, res) => {
- try {
- const [rows] = await promisePool.query('SELECT * FROM users');
- res.json({
- success: true,
- data: rows
- });
- } catch (error) {
- console.error('Error fetching users:', error);
- res.status(500).json({
- success: false,
- message: 'Error fetching users',
- error: error.message
- });
- }
- });
- // 获取单个用户
- app.get('/api/users/:id', async (req, res) => {
- try {
- const { id } = req.params;
- const [rows] = await promisePool.query('SELECT * FROM users WHERE id = ?', [id]);
-
- if (rows.length === 0) {
- return res.status(404).json({
- success: false,
- message: 'User not found'
- });
- }
-
- res.json({
- success: true,
- data: rows[0]
- });
- } catch (error) {
- console.error('Error fetching user:', error);
- res.status(500).json({
- success: false,
- message: 'Error fetching user',
- error: error.message
- });
- }
- });
- // 创建用户
- app.post('/api/users', async (req, res) => {
- try {
- const { name, email } = req.body;
-
- if (!name || !email) {
- return res.status(400).json({
- success: false,
- message: 'Name and email are required'
- });
- }
-
- const [result] = await promisePool.query(
- 'INSERT INTO users (name, email) VALUES (?, ?)',
- [name, email]
- );
-
- const [newUser] = await promisePool.query(
- 'SELECT * FROM users WHERE id = ?',
- [result.insertId]
- );
-
- res.status(201).json({
- success: true,
- data: newUser[0]
- });
- } catch (error) {
- console.error('Error creating user:', error);
-
- if (error.code === 'ER_DUP_ENTRY') {
- return res.status(400).json({
- success: false,
- message: 'Email already exists'
- });
- }
-
- res.status(500).json({
- success: false,
- message: 'Error creating user',
- error: error.message
- });
- }
- });
- // 更新用户
- app.put('/api/users/:id', async (req, res) => {
- try {
- const { id } = req.params;
- const { name, email } = req.body;
-
- if (!name || !email) {
- return res.status(400).json({
- success: false,
- message: 'Name and email are required'
- });
- }
-
- const [result] = await promisePool.query(
- 'UPDATE users SET name = ?, email = ? WHERE id = ?',
- [name, email, id]
- );
-
- if (result.affectedRows === 0) {
- return res.status(404).json({
- success: false,
- message: 'User not found'
- });
- }
-
- const [updatedUser] = await promisePool.query(
- 'SELECT * FROM users WHERE id = ?',
- [id]
- );
-
- res.json({
- success: true,
- data: updatedUser[0]
- });
- } catch (error) {
- console.error('Error updating user:', error);
-
- if (error.code === 'ER_DUP_ENTRY') {
- return res.status(400).json({
- success: false,
- message: 'Email already exists'
- });
- }
-
- res.status(500).json({
- success: false,
- message: 'Error updating user',
- error: error.message
- });
- }
- });
- // 删除用户
- app.delete('/api/users/:id', async (req, res) => {
- try {
- const { id } = req.params;
- const [result] = await promisePool.query('DELETE FROM users WHERE id = ?', [id]);
-
- if (result.affectedRows === 0) {
- return res.status(404).json({
- success: false,
- message: 'User not found'
- });
- }
-
- res.json({
- success: true,
- message: 'User deleted successfully'
- });
- } catch (error) {
- console.error('Error deleting user:', error);
- res.status(500).json({
- success: false,
- message: 'Error deleting user',
- error: error.message
- });
- }
- });
- // 启动服务器
- app.listen(PORT, async () => {
- console.log(`Server running on port ${PORT}`);
- await initializeDatabase();
- });
复制代码
3. 测试API
你可以使用Postman、curl或任何其他API测试工具来测试这个API。
- curl -X POST http://localhost:3000/api/users \
- -H "Content-Type: application/json" \
- -d '{"name": "John Doe", "email": "john@example.com"}'
复制代码- curl http://localhost:3000/api/users
复制代码- curl http://localhost:3000/api/users/1
复制代码- curl -X PUT http://localhost:3000/api/users/1 \
- -H "Content-Type: application/json" \
- -d '{"name": "John Updated", "email": "john.updated@example.com"}'
复制代码- curl -X DELETE http://localhost:3000/api/users/1
复制代码
六、最佳实践与性能优化
1. 使用连接池
如前所述,使用连接池可以显著提高应用性能,避免频繁创建和销毁连接的开销。
2. 实施适当的错误处理
始终为数据库操作实施适当的错误处理,以防止未捕获的异常导致应用崩溃。
- async function safeDatabaseOperation() {
- try {
- // 数据库操作
- const [rows] = await promisePool.query('SELECT * FROM users');
- return rows;
- } catch (error) {
- // 根据错误类型进行适当处理
- if (error.code === 'PROTOCOL_CONNECTION_LOST') {
- console.error('Database connection was lost.');
- // 尝试重新连接或通知用户
- } else if (error.code === 'ER_DUP_ENTRY') {
- console.error('Duplicate entry error.');
- // 处理重复条目错误
- } else {
- console.error('Database error:', error);
- }
- throw error; // 重新抛出错误以便上层处理
- }
- }
复制代码
3. 使用索引优化查询性能
为经常查询的列创建索引可以显著提高查询性能。
- async function createIndexes() {
- try {
- // 为email列创建唯一索引(如果已存在则忽略)
- await promisePool.query(
- 'CREATE UNIQUE INDEX IF NOT EXISTS idx_users_email ON users(email)'
- );
-
- // 为name列创建普通索引
- await promisePool.query(
- 'CREATE INDEX IF NOT EXISTS idx_users_name ON users(name)'
- );
-
- console.log('Indexes created successfully');
- } catch (error) {
- console.error('Error creating indexes:', error);
- throw error;
- }
- }
复制代码
4. 实施数据验证
在将数据发送到数据库之前,始终在应用层实施数据验证。
- const Joi = require('joi'); // 需要安装: npm install joi
- const userSchema = Joi.object({
- name: Joi.string().min(3).max(255).required(),
- email: Joi.string().email().required()
- });
- function validateUser(user) {
- return userSchema.validate(user);
- }
- // 在创建用户前使用
- app.post('/api/users', async (req, res) => {
- const { error } = validateUser(req.body);
- if (error) {
- return res.status(400).json({
- success: false,
- message: error.details[0].message
- });
- }
-
- // 继续处理用户创建...
- });
复制代码
5. 实施缓存策略
对于频繁访问但不经常更改的数据,实施缓存策略可以减少数据库负载。
- const NodeCache = require('node-cache'); // 需要安装: npm install node-cache
- const userCache = new NodeCache({ stdTTL: 300 }); // 缓存5分钟
- async function getUserWithCache(id) {
- // 首先检查缓存
- const cachedUser = userCache.get(id);
- if (cachedUser) {
- return cachedUser;
- }
-
- // 如果不在缓存中,查询数据库
- try {
- const [rows] = await promisePool.query('SELECT * FROM users WHERE id = ?', [id]);
- if (rows.length > 0) {
- // 将结果存入缓存
- userCache.set(id, rows[0]);
- return rows[0];
- }
- return null;
- } catch (error) {
- console.error('Error fetching user:', error);
- throw error;
- }
- }
- // 当用户更新时,清除缓存
- async function updateUser(id, userData) {
- try {
- // 更新数据库
- await promisePool.query(
- 'UPDATE users SET name = ?, email = ? WHERE id = ?',
- [userData.name, userData.email, id]
- );
-
- // 清除缓存
- userCache.del(id);
-
- // 返回更新后的用户
- return getUserWithCache(id);
- } catch (error) {
- console.error('Error updating user:', error);
- throw error;
- }
- }
复制代码
6. 使用ORM简化数据库操作
对于复杂项目,考虑使用ORM(Object-Relational Mapping)库如Sequelize或TypeORM,它们可以简化数据库操作并提供额外功能如数据验证、关联管理等。
- const { Sequelize, DataTypes } = require('sequelize');
- // 初始化Sequelize
- const sequelize = new Sequelize(
- process.env.DB_DATABASE,
- process.env.DB_USER,
- process.env.DB_PASSWORD,
- {
- host: process.env.DB_HOST,
- dialect: 'mysql'
- }
- );
- // 定义用户模型
- const User = sequelize.define('User', {
- name: {
- type: DataTypes.STRING,
- allowNull: false
- },
- email: {
- type: DataTypes.STRING,
- allowNull: false,
- unique: true
- }
- });
- // 同步模型到数据库
- sequelize.sync();
- // 使用模型进行CRUD操作
- async function sequelizeExample() {
- try {
- // 创建用户
- const newUser = await User.create({
- name: 'Jane Smith',
- email: 'jane@example.com'
- });
- console.log('Created user:', newUser.toJSON());
-
- // 查询用户
- const users = await User.findAll();
- console.log('All users:', users.map(u => u.toJSON()));
-
- // 更新用户
- await User.update(
- { name: 'Jane Updated' },
- { where: { id: newUser.id } }
- );
-
- // 删除用户
- await User.destroy({
- where: { id: newUser.id }
- });
- } catch (error) {
- console.error('Sequelize error:', error);
- }
- }
- sequelizeExample();
复制代码
七、总结
通过本指南,我们全面了解了如何在Node.js应用中连接和操作MySQL数据库。从基础的环境配置到复杂的数据库操作,再到构建完整的RESTful API,我们涵盖了全栈开发中与数据库交互的各个方面。
关键要点包括:
1. 环境配置:正确安装和配置Node.js与MySQL是开发的基础。
2. 连接管理:使用连接池可以提高应用性能和资源利用率。
3. 基本CRUD操作:掌握创建、读取、更新和删除数据的基本操作。
4. 高级功能:事务处理、预处理语句和异步操作处理是构建健壮应用的关键。
5. 实战应用:通过构建RESTful API,将理论知识应用到实际项目中。
6. 最佳实践:实施适当的错误处理、数据验证、缓存策略和使用ORM等最佳实践,可以提高应用的性能和可维护性。
随着你对Node.js和MySQL的深入理解,你将能够构建更加复杂和高效的全栈应用。不断实践和探索新的技术,你将成为一名真正的全栈开发高手。
希望本指南能够帮助你在Node.js与MySQL开发的道路上取得成功! |
|