活动公告

系统通知
05-18 21:22
系统通知
通知:本站资源由网友上传分享,如有违规等问题请到版务模块进行投诉,资源失效请在帖子内回复要求补档,会尽快处理!
10-23 09:31

Node.js与MySQL数据库连接完全指南从环境配置到连接建立再到数据增删改查操作全方位解析助你成为全栈开发高手

SunJu_FaceMall

3万

主题

2860

科技点

3万

积分

白金月票

碾压王

积分
32872

塔罗立华奏

<font color=白金月票" /> 发表于 2025-9-26 00:30:33 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

x
引言

Node.js作为当今流行的后端JavaScript运行环境,与MySQL这一广泛应用的关系型数据库相结合,为全栈开发提供了强大而灵活的解决方案。本指南将带你从零开始,逐步掌握Node.js与MySQL的连接技术,从基础的环境配置到复杂的数据库操作,帮助你构建高效、安全的数据驱动应用。

一、环境配置

1. Node.js安装与配置

首先,确保你的系统已安装Node.js。如果尚未安装,请访问Node.js官网下载并安装最新的LTS版本。

安装完成后,在终端中运行以下命令验证安装:
  1. node -v
  2. npm -v
复制代码

你将看到类似以下的输出,显示安装的Node.js和npm版本:
  1. v18.17.0
  2. 9.6.7
复制代码

2. MySQL安装与配置

1. 访问MySQL官网下载MySQL Installer
2. 运行安装程序,选择”Full”安装类型以包含所有组件
3. 在配置过程中,设置root用户密码并记住它
4. 完成安装后,确保MySQL服务已启动

使用Homebrew安装MySQL:
  1. brew update
  2. brew install mysql
复制代码

安装完成后,启动MySQL服务:
  1. brew services start mysql
复制代码

对于Ubuntu/Debian系统:
  1. sudo apt update
  2. sudo apt install mysql-server
  3. sudo mysql_secure_installation
复制代码

对于CentOS/RHEL系统:
  1. sudo yum update
  2. sudo yum install mysql-server
  3. sudo systemctl start mysqld
  4. sudo systemctl enable mysqld
复制代码

在终端中运行以下命令登录MySQL:
  1. mysql -u root -p
复制代码

输入你设置的root密码,成功登录后将看到MySQL命令行提示符:
  1. mysql>
复制代码

二、连接建立

1. 创建Node.js项目

首先,创建一个新的项目目录并初始化npm项目:
  1. mkdir node-mysql-guide
  2. cd node-mysql-guide
  3. npm init -y
复制代码

2. 安装MySQL驱动

Node.js有多种MySQL驱动可供选择,最常用的是mysql和mysql2。mysql2是mysql的增强版,提供了更好的性能和Promise支持。
  1. npm install mysql2
复制代码

3. 基本连接示例

创建一个名为app.js的文件,添加以下代码:
  1. const mysql = require('mysql2');
  2. // 创建连接配置
  3. const connection = mysql.createConnection({
  4.   host: 'localhost',
  5.   user: 'root',
  6.   password: 'your_password', // 替换为你的MySQL密码
  7.   database: 'my_database'    // 可选,指定要连接的数据库
  8. });
  9. // 连接到MySQL
  10. connection.connect(error => {
  11.   if (error) {
  12.     console.error('Error connecting to the database: ' + error.stack);
  13.     return;
  14.   }
  15.   console.log('Connected to MySQL with id ' + connection.threadId);
  16.   
  17.   // 在这里执行数据库操作
  18.   
  19.   // 关闭连接
  20.   connection.end();
  21. });
复制代码

运行这个文件:
  1. node app.js
复制代码

如果一切正常,你将看到连接成功的消息。

4. 使用连接池

在生产环境中,推荐使用连接池来管理数据库连接,以提高性能和资源利用率。
  1. const mysql = require('mysql2');
  2. // 创建连接池
  3. const pool = mysql.createPool({
  4.   host: 'localhost',
  5.   user: 'root',
  6.   password: 'your_password',
  7.   database: 'my_database',
  8.   waitForConnections: true,
  9.   connectionLimit: 10,  // 连接池大小
  10.   queueLimit: 0
  11. });
  12. // 将连接池转换为Promise支持
  13. const promisePool = pool.promise();
  14. // 使用连接池查询数据库
  15. async function queryDatabase() {
  16.   try {
  17.     const [rows, fields] = await promisePool.query('SELECT * FROM users');
  18.     console.log(rows);
  19.   } catch (error) {
  20.     console.error('Error querying database:', error);
  21.   }
  22. }
  23. queryDatabase();
复制代码

5. 使用环境变量管理敏感信息

在实际项目中,不应将数据库凭据硬编码在代码中。使用dotenv包从环境变量加载配置:
  1. npm install dotenv
复制代码

在项目根目录创建.env文件:
  1. DB_HOST=localhost
  2. DB_USER=root
  3. DB_PASSWORD=your_password
  4. DB_DATABASE=my_database
复制代码

修改连接代码:
  1. require('dotenv').config();
  2. const mysql = require('mysql2');
  3. const pool = mysql.createPool({
  4.   host: process.env.DB_HOST,
  5.   user: process.env.DB_USER,
  6.   password: process.env.DB_PASSWORD,
  7.   database: process.env.DB_DATABASE,
  8.   waitForConnections: true,
  9.   connectionLimit: 10,
  10.   queueLimit: 0
  11. });
  12. const promisePool = pool.promise();
  13. module.exports = promisePool;
复制代码

三、数据库操作

1. 创建数据库和表

首先,让我们创建一个示例数据库和表:
  1. const promisePool = require('./db'); // 假设上面的连接池代码保存在db.js中
  2. async function setupDatabase() {
  3.   try {
  4.     // 创建数据库(如果不存在)
  5.     await promisePool.query('CREATE DATABASE IF NOT EXISTS my_app_db');
  6.     console.log('Database created or already exists');
  7.    
  8.     // 使用数据库
  9.     await promisePool.query('USE my_app_db');
  10.    
  11.     // 创建用户表
  12.     const createUsersTable = `
  13.       CREATE TABLE IF NOT EXISTS users (
  14.         id INT AUTO_INCREMENT PRIMARY KEY,
  15.         name VARCHAR(255) NOT NULL,
  16.         email VARCHAR(255) NOT NULL UNIQUE,
  17.         created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
  18.       )
  19.     `;
  20.     await promisePool.query(createUsersTable);
  21.     console.log('Users table created or already exists');
  22.    
  23.     // 创建产品表
  24.     const createProductsTable = `
  25.       CREATE TABLE IF NOT EXISTS products (
  26.         id INT AUTO_INCREMENT PRIMARY KEY,
  27.         name VARCHAR(255) NOT NULL,
  28.         price DECIMAL(10, 2) NOT NULL,
  29.         stock_quantity INT NOT NULL DEFAULT 0,
  30.         created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
  31.       )
  32.     `;
  33.     await promisePool.query(createProductsTable);
  34.     console.log('Products table created or already exists');
  35.    
  36.     // 创建订单表
  37.     const createOrdersTable = `
  38.       CREATE TABLE IF NOT EXISTS orders (
  39.         id INT AUTO_INCREMENT PRIMARY KEY,
  40.         user_id INT NOT NULL,
  41.         total_amount DECIMAL(10, 2) NOT NULL,
  42.         order_date TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
  43.         FOREIGN KEY (user_id) REFERENCES users(id)
  44.       )
  45.     `;
  46.     await promisePool.query(createOrdersTable);
  47.     console.log('Orders table created or already exists');
  48.    
  49.   } catch (error) {
  50.     console.error('Error setting up database:', error);
  51.   }
  52. }
  53. setupDatabase();
复制代码

2. 插入数据(Create)
  1. async function insertUser(name, email) {
  2.   try {
  3.     const sql = 'INSERT INTO users (name, email) VALUES (?, ?)';
  4.     const [result] = await promisePool.query(sql, [name, email]);
  5.     console.log('User inserted with ID:', result.insertId);
  6.     return result.insertId;
  7.   } catch (error) {
  8.     console.error('Error inserting user:', error);
  9.     throw error;
  10.   }
  11. }
  12. // 使用示例
  13. insertUser('John Doe', 'john@example.com')
  14.   .then(id => console.log('New user ID:', id))
  15.   .catch(error => console.error('Failed to insert user:', error));
复制代码
  1. async function insertMultipleUsers(users) {
  2.   try {
  3.     const sql = 'INSERT INTO users (name, email) VALUES ?';
  4.     const values = users.map(user => [user.name, user.email]);
  5.     const [result] = await promisePool.query(sql, [values]);
  6.     console.log(`${result.affectedRows} users inserted`);
  7.     return result.affectedRows;
  8.   } catch (error) {
  9.     console.error('Error inserting multiple users:', error);
  10.     throw error;
  11.   }
  12. }
  13. // 使用示例
  14. const newUsers = [
  15.   { name: 'Alice Johnson', email: 'alice@example.com' },
  16.   { name: 'Bob Smith', email: 'bob@example.com' },
  17.   { name: 'Charlie Brown', email: 'charlie@example.com' }
  18. ];
  19. insertMultipleUsers(newUsers)
  20.   .then(count => console.log(`${count} users inserted`))
  21.   .catch(error => console.error('Failed to insert users:', error));
复制代码

3. 查询数据(Read)
  1. async function getAllUsers() {
  2.   try {
  3.     const [rows] = await promisePool.query('SELECT * FROM users');
  4.     return rows;
  5.   } catch (error) {
  6.     console.error('Error fetching users:', error);
  7.     throw error;
  8.   }
  9. }
  10. // 使用示例
  11. getAllUsers()
  12.   .then(users => console.log('All users:', users))
  13.   .catch(error => console.error('Failed to fetch users:', error));
复制代码
  1. async function getUserById(id) {
  2.   try {
  3.     const [rows] = await promisePool.query('SELECT * FROM users WHERE id = ?', [id]);
  4.     if (rows.length > 0) {
  5.       return rows[0];
  6.     }
  7.     return null; // 用户不存在
  8.   } catch (error) {
  9.     console.error('Error fetching user by ID:', error);
  10.     throw error;
  11.   }
  12. }
  13. // 使用示例
  14. getUserById(1)
  15.   .then(user => {
  16.     if (user) {
  17.       console.log('Found user:', user);
  18.     } else {
  19.       console.log('User not found');
  20.     }
  21.   })
  22.   .catch(error => console.error('Failed to fetch user:', error));
复制代码
  1. async function searchUsersByName(searchTerm) {
  2.   try {
  3.     const [rows] = await promisePool.query(
  4.       'SELECT * FROM users WHERE name LIKE ?',
  5.       [`%${searchTerm}%`]
  6.     );
  7.     return rows;
  8.   } catch (error) {
  9.     console.error('Error searching users by name:', error);
  10.     throw error;
  11.   }
  12. }
  13. // 使用示例
  14. searchUsersByName('John')
  15.   .then(users => console.log('Users matching "John":', users))
  16.   .catch(error => console.error('Failed to search users:', error));
复制代码
  1. async function getUsersPaginated(page = 1, pageSize = 10) {
  2.   try {
  3.     const offset = (page - 1) * pageSize;
  4.     const [rows] = await promisePool.query(
  5.       'SELECT * FROM users LIMIT ? OFFSET ?',
  6.       [pageSize, offset]
  7.     );
  8.    
  9.     // 获取总记录数
  10.     const [countResult] = await promisePool.query('SELECT COUNT(*) as total FROM users');
  11.     const total = countResult[0].total;
  12.    
  13.     return {
  14.       data: rows,
  15.       pagination: {
  16.         page,
  17.         pageSize,
  18.         total,
  19.         totalPages: Math.ceil(total / pageSize)
  20.       }
  21.     };
  22.   } catch (error) {
  23.     console.error('Error fetching paginated users:', error);
  24.     throw error;
  25.   }
  26. }
  27. // 使用示例
  28. getUsersPaginated(1, 5)
  29.   .then(result => {
  30.     console.log('Page data:', result.data);
  31.     console.log('Pagination info:', result.pagination);
  32.   })
  33.   .catch(error => console.error('Failed to fetch paginated users:', error));
复制代码

4. 更新数据(Update)
  1. async function updateUserEmail(id, newEmail) {
  2.   try {
  3.     const [result] = await promisePool.query(
  4.       'UPDATE users SET email = ? WHERE id = ?',
  5.       [newEmail, id]
  6.     );
  7.    
  8.     if (result.affectedRows === 0) {
  9.       return false; // 用户不存在
  10.     }
  11.    
  12.     console.log('User email updated');
  13.     return true;
  14.   } catch (error) {
  15.     console.error('Error updating user email:', error);
  16.     throw error;
  17.   }
  18. }
  19. // 使用示例
  20. updateUserEmail(1, 'new.email@example.com')
  21.   .then(success => {
  22.     if (success) {
  23.       console.log('Email updated successfully');
  24.     } else {
  25.       console.log('User not found');
  26.     }
  27.   })
  28.   .catch(error => console.error('Failed to update email:', error));
复制代码
  1. async function updateMultipleUsers(updates) {
  2.   try {
  3.     // 使用CASE语句进行批量更新
  4.     let sql = 'UPDATE users SET email = CASE id ';
  5.     const ids = [];
  6.     const emails = [];
  7.    
  8.     updates.forEach(update => {
  9.       sql += 'WHEN ? THEN ? ';
  10.       ids.push(update.id);
  11.       emails.push(update.email);
  12.     });
  13.    
  14.     sql += 'END WHERE id IN (';
  15.     sql += ids.map(() => '?').join(',');
  16.     sql += ')';
  17.    
  18.     const params = [...ids, ...emails, ...ids];
  19.     const [result] = await promisePool.query(sql, params);
  20.    
  21.     console.log(`${result.affectedRows} users updated`);
  22.     return result.affectedRows;
  23.   } catch (error) {
  24.     console.error('Error updating multiple users:', error);
  25.     throw error;
  26.   }
  27. }
  28. // 使用示例
  29. const updates = [
  30.   { id: 1, email: 'updated1@example.com' },
  31.   { id: 2, email: 'updated2@example.com' },
  32.   { id: 3, email: 'updated3@example.com' }
  33. ];
  34. updateMultipleUsers(updates)
  35.   .then(count => console.log(`${count} users updated`))
  36.   .catch(error => console.error('Failed to update users:', error));
复制代码

5. 删除数据(Delete)
  1. async function deleteUser(id) {
  2.   try {
  3.     const [result] = await promisePool.query('DELETE FROM users WHERE id = ?', [id]);
  4.    
  5.     if (result.affectedRows === 0) {
  6.       return false; // 用户不存在
  7.     }
  8.    
  9.     console.log('User deleted');
  10.     return true;
  11.   } catch (error) {
  12.     console.error('Error deleting user:', error);
  13.     throw error;
  14.   }
  15. }
  16. // 使用示例
  17. deleteUser(1)
  18.   .then(success => {
  19.     if (success) {
  20.       console.log('User deleted successfully');
  21.     } else {
  22.       console.log('User not found');
  23.     }
  24.   })
  25.   .catch(error => console.error('Failed to delete user:', error));
复制代码
  1. async function deleteMultipleUsers(ids) {
  2.   try {
  3.     const [result] = await promisePool.query(
  4.       'DELETE FROM users WHERE id IN (?)',
  5.       [ids]
  6.     );
  7.    
  8.     console.log(`${result.affectedRows} users deleted`);
  9.     return result.affectedRows;
  10.   } catch (error) {
  11.     console.error('Error deleting multiple users:', error);
  12.     throw error;
  13.   }
  14. }
  15. // 使用示例
  16. deleteMultipleUsers([2, 3, 4])
  17.   .then(count => console.log(`${count} users deleted`))
  18.   .catch(error => console.error('Failed to delete users:', error));
复制代码

四、高级操作

1. 事务处理

事务是一组SQL语句的集合,这些语句要么全部执行成功,要么全部失败回滚。在处理需要多个步骤的操作时,事务非常重要。
  1. async function placeOrder(userId, productIds) {
  2.   const connection = await promisePool.getConnection();
  3.   
  4.   try {
  5.     // 开始事务
  6.     await connection.beginTransaction();
  7.    
  8.     // 获取用户信息
  9.     const [users] = await connection.query('SELECT * FROM users WHERE id = ?', [userId]);
  10.     if (users.length === 0) {
  11.       throw new Error('User not found');
  12.     }
  13.    
  14.     // 计算订单总额
  15.     let totalAmount = 0;
  16.     for (const productId of productIds) {
  17.       const [products] = await connection.query('SELECT * FROM products WHERE id = ?', [productId]);
  18.       if (products.length === 0) {
  19.         throw new Error(`Product with ID ${productId} not found`);
  20.       }
  21.       totalAmount += parseFloat(products[0].price);
  22.     }
  23.    
  24.     // 创建订单
  25.     const [orderResult] = await connection.query(
  26.       'INSERT INTO orders (user_id, total_amount) VALUES (?, ?)',
  27.       [userId, totalAmount]
  28.     );
  29.     const orderId = orderResult.insertId;
  30.    
  31.     // 更新产品库存
  32.     for (const productId of productIds) {
  33.       await connection.query(
  34.         'UPDATE products SET stock_quantity = stock_quantity - 1 WHERE id = ?',
  35.         [productId]
  36.       );
  37.     }
  38.    
  39.     // 提交事务
  40.     await connection.commit();
  41.     console.log('Order placed successfully');
  42.     return orderId;
  43.    
  44.   } catch (error) {
  45.     // 发生错误,回滚事务
  46.     await connection.rollback();
  47.     console.error('Error placing order:', error);
  48.     throw error;
  49.   } finally {
  50.     // 释放连接回连接池
  51.     connection.release();
  52.   }
  53. }
  54. // 使用示例
  55. placeOrder(1, [1, 2, 3])
  56.   .then(orderId => console.log('Order placed with ID:', orderId))
  57.   .catch(error => console.error('Failed to place order:', error));
复制代码

2. 预处理语句防止SQL注入

SQL注入是一种常见的网络安全漏洞,通过使用预处理语句(参数化查询),可以有效防止SQL注入攻击。
  1. async function safeUserLogin(email, password) {
  2.   try {
  3.     // 使用预处理语句防止SQL注入
  4.     const [rows] = await promisePool.query(
  5.       'SELECT * FROM users WHERE email = ? AND password = ?',
  6.       [email, password]
  7.     );
  8.    
  9.     if (rows.length > 0) {
  10.       // 不返回密码等敏感信息
  11.       const { password, ...userWithoutPassword } = rows[0];
  12.       return userWithoutPassword;
  13.     }
  14.    
  15.     return null; // 认证失败
  16.   } catch (error) {
  17.     console.error('Error during user login:', error);
  18.     throw error;
  19.   }
  20. }
  21. // 使用示例
  22. safeUserLogin('user@example.com', 'securepassword123')
  23.   .then(user => {
  24.     if (user) {
  25.       console.log('Login successful. User:', user);
  26.     } else {
  27.       console.log('Login failed. Invalid email or password.');
  28.     }
  29.   })
  30.   .catch(error => console.error('Login error:', error));
复制代码

3. 异步操作处理

Node.js的异步特性使得处理数据库操作时需要特别注意。以下是使用async/await处理异步操作的示例:
  1. class UserService {
  2.   constructor(dbPool) {
  3.     this.dbPool = dbPool;
  4.   }
  5.   
  6.   async createUser(userData) {
  7.     try {
  8.       const { name, email } = userData;
  9.       const [result] = await this.dbPool.query(
  10.         'INSERT INTO users (name, email) VALUES (?, ?)',
  11.         [name, email]
  12.       );
  13.       
  14.       // 获取新创建的用户
  15.       const [newUser] = await this.dbPool.query(
  16.         'SELECT * FROM users WHERE id = ?',
  17.         [result.insertId]
  18.       );
  19.       
  20.       return newUser[0];
  21.     } catch (error) {
  22.       if (error.code === 'ER_DUP_ENTRY') {
  23.         throw new Error('Email already exists');
  24.       }
  25.       console.error('Error creating user:', error);
  26.       throw error;
  27.     }
  28.   }
  29.   
  30.   async getUserWithOrders(userId) {
  31.     try {
  32.       // 并行执行多个查询
  33.       const [userResult, ordersResult] = await Promise.all([
  34.         this.dbPool.query('SELECT * FROM users WHERE id = ?', [userId]),
  35.         this.dbPool.query('SELECT * FROM orders WHERE user_id = ?', [userId])
  36.       ]);
  37.       
  38.       const user = userResult[0][0];
  39.       const orders = ordersResult[0];
  40.       
  41.       if (!user) {
  42.         return null;
  43.       }
  44.       
  45.       // 返回用户及其订单
  46.       return {
  47.         ...user,
  48.         orders
  49.       };
  50.     } catch (error) {
  51.       console.error('Error fetching user with orders:', error);
  52.       throw error;
  53.     }
  54.   }
  55. }
  56. // 使用示例
  57. const userService = new UserService(promisePool);
  58. // 创建用户
  59. userService.createUser({ name: 'Jane Doe', email: 'jane@example.com' })
  60.   .then(user => {
  61.     console.log('Created user:', user);
  62.     // 获取用户及其订单
  63.     return userService.getUserWithOrders(user.id);
  64.   })
  65.   .then(userWithOrders => {
  66.     if (userWithOrders) {
  67.       console.log('User with orders:', userWithOrders);
  68.     } else {
  69.       console.log('User not found');
  70.     }
  71.   })
  72.   .catch(error => console.error('Error:', error));
复制代码

五、实战案例:构建一个简单的RESTful API

让我们使用Express框架和MySQL构建一个简单的用户管理API。

1. 安装必要的依赖
  1. npm install express body-parser cors
复制代码

2. 创建API服务器

创建一个名为server.js的文件:
  1. require('dotenv').config();
  2. const express = require('express');
  3. const bodyParser = require('body-parser');
  4. const cors = require('cors');
  5. const mysql = require('mysql2');
  6. const app = express();
  7. const PORT = process.env.PORT || 3000;
  8. // 中间件
  9. app.use(bodyParser.json());
  10. app.use(cors());
  11. // MySQL连接池
  12. const pool = mysql.createPool({
  13.   host: process.env.DB_HOST,
  14.   user: process.env.DB_USER,
  15.   password: process.env.DB_PASSWORD,
  16.   database: process.env.DB_DATABASE,
  17.   waitForConnections: true,
  18.   connectionLimit: 10,
  19.   queueLimit: 0
  20. });
  21. const promisePool = pool.promise();
  22. // 确保数据库和表存在
  23. async function initializeDatabase() {
  24.   try {
  25.     await promisePool.query('CREATE DATABASE IF NOT EXISTS my_app_db');
  26.     await promisePool.query('USE my_app_db');
  27.    
  28.     const createUsersTable = `
  29.       CREATE TABLE IF NOT EXISTS users (
  30.         id INT AUTO_INCREMENT PRIMARY KEY,
  31.         name VARCHAR(255) NOT NULL,
  32.         email VARCHAR(255) NOT NULL UNIQUE,
  33.         created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
  34.       )
  35.     `;
  36.     await promisePool.query(createUsersTable);
  37.     console.log('Database initialized');
  38.   } catch (error) {
  39.     console.error('Error initializing database:', error);
  40.   }
  41. }
  42. // API路由
  43. // 获取所有用户
  44. app.get('/api/users', async (req, res) => {
  45.   try {
  46.     const [rows] = await promisePool.query('SELECT * FROM users');
  47.     res.json({
  48.       success: true,
  49.       data: rows
  50.     });
  51.   } catch (error) {
  52.     console.error('Error fetching users:', error);
  53.     res.status(500).json({
  54.       success: false,
  55.       message: 'Error fetching users',
  56.       error: error.message
  57.     });
  58.   }
  59. });
  60. // 获取单个用户
  61. app.get('/api/users/:id', async (req, res) => {
  62.   try {
  63.     const { id } = req.params;
  64.     const [rows] = await promisePool.query('SELECT * FROM users WHERE id = ?', [id]);
  65.    
  66.     if (rows.length === 0) {
  67.       return res.status(404).json({
  68.         success: false,
  69.         message: 'User not found'
  70.       });
  71.     }
  72.    
  73.     res.json({
  74.       success: true,
  75.       data: rows[0]
  76.     });
  77.   } catch (error) {
  78.     console.error('Error fetching user:', error);
  79.     res.status(500).json({
  80.       success: false,
  81.       message: 'Error fetching user',
  82.       error: error.message
  83.     });
  84.   }
  85. });
  86. // 创建用户
  87. app.post('/api/users', async (req, res) => {
  88.   try {
  89.     const { name, email } = req.body;
  90.    
  91.     if (!name || !email) {
  92.       return res.status(400).json({
  93.         success: false,
  94.         message: 'Name and email are required'
  95.       });
  96.     }
  97.    
  98.     const [result] = await promisePool.query(
  99.       'INSERT INTO users (name, email) VALUES (?, ?)',
  100.       [name, email]
  101.     );
  102.    
  103.     const [newUser] = await promisePool.query(
  104.       'SELECT * FROM users WHERE id = ?',
  105.       [result.insertId]
  106.     );
  107.    
  108.     res.status(201).json({
  109.       success: true,
  110.       data: newUser[0]
  111.     });
  112.   } catch (error) {
  113.     console.error('Error creating user:', error);
  114.    
  115.     if (error.code === 'ER_DUP_ENTRY') {
  116.       return res.status(400).json({
  117.         success: false,
  118.         message: 'Email already exists'
  119.       });
  120.     }
  121.    
  122.     res.status(500).json({
  123.       success: false,
  124.       message: 'Error creating user',
  125.       error: error.message
  126.     });
  127.   }
  128. });
  129. // 更新用户
  130. app.put('/api/users/:id', async (req, res) => {
  131.   try {
  132.     const { id } = req.params;
  133.     const { name, email } = req.body;
  134.    
  135.     if (!name || !email) {
  136.       return res.status(400).json({
  137.         success: false,
  138.         message: 'Name and email are required'
  139.       });
  140.     }
  141.    
  142.     const [result] = await promisePool.query(
  143.       'UPDATE users SET name = ?, email = ? WHERE id = ?',
  144.       [name, email, id]
  145.     );
  146.    
  147.     if (result.affectedRows === 0) {
  148.       return res.status(404).json({
  149.         success: false,
  150.         message: 'User not found'
  151.       });
  152.     }
  153.    
  154.     const [updatedUser] = await promisePool.query(
  155.       'SELECT * FROM users WHERE id = ?',
  156.       [id]
  157.     );
  158.    
  159.     res.json({
  160.       success: true,
  161.       data: updatedUser[0]
  162.     });
  163.   } catch (error) {
  164.     console.error('Error updating user:', error);
  165.    
  166.     if (error.code === 'ER_DUP_ENTRY') {
  167.       return res.status(400).json({
  168.         success: false,
  169.         message: 'Email already exists'
  170.       });
  171.     }
  172.    
  173.     res.status(500).json({
  174.       success: false,
  175.       message: 'Error updating user',
  176.       error: error.message
  177.     });
  178.   }
  179. });
  180. // 删除用户
  181. app.delete('/api/users/:id', async (req, res) => {
  182.   try {
  183.     const { id } = req.params;
  184.     const [result] = await promisePool.query('DELETE FROM users WHERE id = ?', [id]);
  185.    
  186.     if (result.affectedRows === 0) {
  187.       return res.status(404).json({
  188.         success: false,
  189.         message: 'User not found'
  190.       });
  191.     }
  192.    
  193.     res.json({
  194.       success: true,
  195.       message: 'User deleted successfully'
  196.     });
  197.   } catch (error) {
  198.     console.error('Error deleting user:', error);
  199.     res.status(500).json({
  200.       success: false,
  201.       message: 'Error deleting user',
  202.       error: error.message
  203.     });
  204.   }
  205. });
  206. // 启动服务器
  207. app.listen(PORT, async () => {
  208.   console.log(`Server running on port ${PORT}`);
  209.   await initializeDatabase();
  210. });
复制代码

3. 测试API

你可以使用Postman、curl或任何其他API测试工具来测试这个API。
  1. curl -X POST http://localhost:3000/api/users \
  2.   -H "Content-Type: application/json" \
  3.   -d '{"name": "John Doe", "email": "john@example.com"}'
复制代码
  1. curl http://localhost:3000/api/users
复制代码
  1. curl http://localhost:3000/api/users/1
复制代码
  1. curl -X PUT http://localhost:3000/api/users/1 \
  2.   -H "Content-Type: application/json" \
  3.   -d '{"name": "John Updated", "email": "john.updated@example.com"}'
复制代码
  1. curl -X DELETE http://localhost:3000/api/users/1
复制代码

六、最佳实践与性能优化

1. 使用连接池

如前所述,使用连接池可以显著提高应用性能,避免频繁创建和销毁连接的开销。

2. 实施适当的错误处理

始终为数据库操作实施适当的错误处理,以防止未捕获的异常导致应用崩溃。
  1. async function safeDatabaseOperation() {
  2.   try {
  3.     // 数据库操作
  4.     const [rows] = await promisePool.query('SELECT * FROM users');
  5.     return rows;
  6.   } catch (error) {
  7.     // 根据错误类型进行适当处理
  8.     if (error.code === 'PROTOCOL_CONNECTION_LOST') {
  9.       console.error('Database connection was lost.');
  10.       // 尝试重新连接或通知用户
  11.     } else if (error.code === 'ER_DUP_ENTRY') {
  12.       console.error('Duplicate entry error.');
  13.       // 处理重复条目错误
  14.     } else {
  15.       console.error('Database error:', error);
  16.     }
  17.     throw error; // 重新抛出错误以便上层处理
  18.   }
  19. }
复制代码

3. 使用索引优化查询性能

为经常查询的列创建索引可以显著提高查询性能。
  1. async function createIndexes() {
  2.   try {
  3.     // 为email列创建唯一索引(如果已存在则忽略)
  4.     await promisePool.query(
  5.       'CREATE UNIQUE INDEX IF NOT EXISTS idx_users_email ON users(email)'
  6.     );
  7.    
  8.     // 为name列创建普通索引
  9.     await promisePool.query(
  10.       'CREATE INDEX IF NOT EXISTS idx_users_name ON users(name)'
  11.     );
  12.    
  13.     console.log('Indexes created successfully');
  14.   } catch (error) {
  15.     console.error('Error creating indexes:', error);
  16.     throw error;
  17.   }
  18. }
复制代码

4. 实施数据验证

在将数据发送到数据库之前,始终在应用层实施数据验证。
  1. const Joi = require('joi'); // 需要安装: npm install joi
  2. const userSchema = Joi.object({
  3.   name: Joi.string().min(3).max(255).required(),
  4.   email: Joi.string().email().required()
  5. });
  6. function validateUser(user) {
  7.   return userSchema.validate(user);
  8. }
  9. // 在创建用户前使用
  10. app.post('/api/users', async (req, res) => {
  11.   const { error } = validateUser(req.body);
  12.   if (error) {
  13.     return res.status(400).json({
  14.       success: false,
  15.       message: error.details[0].message
  16.     });
  17.   }
  18.   
  19.   // 继续处理用户创建...
  20. });
复制代码

5. 实施缓存策略

对于频繁访问但不经常更改的数据,实施缓存策略可以减少数据库负载。
  1. const NodeCache = require('node-cache'); // 需要安装: npm install node-cache
  2. const userCache = new NodeCache({ stdTTL: 300 }); // 缓存5分钟
  3. async function getUserWithCache(id) {
  4.   // 首先检查缓存
  5.   const cachedUser = userCache.get(id);
  6.   if (cachedUser) {
  7.     return cachedUser;
  8.   }
  9.   
  10.   // 如果不在缓存中,查询数据库
  11.   try {
  12.     const [rows] = await promisePool.query('SELECT * FROM users WHERE id = ?', [id]);
  13.     if (rows.length > 0) {
  14.       // 将结果存入缓存
  15.       userCache.set(id, rows[0]);
  16.       return rows[0];
  17.     }
  18.     return null;
  19.   } catch (error) {
  20.     console.error('Error fetching user:', error);
  21.     throw error;
  22.   }
  23. }
  24. // 当用户更新时,清除缓存
  25. async function updateUser(id, userData) {
  26.   try {
  27.     // 更新数据库
  28.     await promisePool.query(
  29.       'UPDATE users SET name = ?, email = ? WHERE id = ?',
  30.       [userData.name, userData.email, id]
  31.     );
  32.    
  33.     // 清除缓存
  34.     userCache.del(id);
  35.    
  36.     // 返回更新后的用户
  37.     return getUserWithCache(id);
  38.   } catch (error) {
  39.     console.error('Error updating user:', error);
  40.     throw error;
  41.   }
  42. }
复制代码

6. 使用ORM简化数据库操作

对于复杂项目,考虑使用ORM(Object-Relational Mapping)库如Sequelize或TypeORM,它们可以简化数据库操作并提供额外功能如数据验证、关联管理等。
  1. npm install sequelize
复制代码
  1. const { Sequelize, DataTypes } = require('sequelize');
  2. // 初始化Sequelize
  3. const sequelize = new Sequelize(
  4.   process.env.DB_DATABASE,
  5.   process.env.DB_USER,
  6.   process.env.DB_PASSWORD,
  7.   {
  8.     host: process.env.DB_HOST,
  9.     dialect: 'mysql'
  10.   }
  11. );
  12. // 定义用户模型
  13. const User = sequelize.define('User', {
  14.   name: {
  15.     type: DataTypes.STRING,
  16.     allowNull: false
  17.   },
  18.   email: {
  19.     type: DataTypes.STRING,
  20.     allowNull: false,
  21.     unique: true
  22.   }
  23. });
  24. // 同步模型到数据库
  25. sequelize.sync();
  26. // 使用模型进行CRUD操作
  27. async function sequelizeExample() {
  28.   try {
  29.     // 创建用户
  30.     const newUser = await User.create({
  31.       name: 'Jane Smith',
  32.       email: 'jane@example.com'
  33.     });
  34.     console.log('Created user:', newUser.toJSON());
  35.    
  36.     // 查询用户
  37.     const users = await User.findAll();
  38.     console.log('All users:', users.map(u => u.toJSON()));
  39.    
  40.     // 更新用户
  41.     await User.update(
  42.       { name: 'Jane Updated' },
  43.       { where: { id: newUser.id } }
  44.     );
  45.    
  46.     // 删除用户
  47.     await User.destroy({
  48.       where: { id: newUser.id }
  49.     });
  50.   } catch (error) {
  51.     console.error('Sequelize error:', error);
  52.   }
  53. }
  54. 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开发的道路上取得成功!
「七転び八起き(ななころびやおき)」
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则