2、MySQL基础与Node.js连接:MySQL安装与配置、使用mysql2驱动连接数据库、连接池配置与最佳实践

好,咱们进入第二章。这一章我打算带你亲手把MySQL跑起来,然后用Node.js连上它。说白了,就是搭好地基。地基稳了,后面ORM、事务、分库分表这些高级玩法才能玩得转。

我个人习惯,不管项目多急,数据库连接这块绝不凑合。你想想看,数据库挂了,整个服务就瘫了。所以这一章,咱们把安装、配置、连接池,一步到位讲清楚。

2.1 MySQL安装与配置

先搞定MySQL。不同系统安装方式不一样,我挑最常见的两种说。

2.1.1 macOS 安装

用Homebrew最省事。打开终端,敲一行命令:

brew install mysql

装完之后,启动服务:

brew services start mysql

然后跑一下安全配置脚本,设置root密码:

mysql_secure_installation

嗯,这里要注意。它会问你一堆问题,比如是否移除匿名用户、是否禁止root远程登录。我建议全选yes。生产环境千万别留匿名用户,这是基本的安全意识。

2.1.2 Ubuntu/Debian 安装

Linux上更直接:

sudo apt update
sudo apt install mysql-server
sudo systemctl start mysql
sudo mysql_secure_installation

装好之后,检查一下状态:

sudo systemctl status mysql

看到 active (running) 就对了。

2.1.3 基础配置要点

MySQL装好后,有几个配置我建议你立刻改掉。打开 /etc/mysql/my.cnf/etc/my.cnf

配置项 推荐值 说明
bind-address 127.0.0.1 只允许本地连接,除非你有远程访问需求
max_connections 200 根据服务器内存调整,别设太大
character-set-server utf8mb4 支持emoji,避免乱码
collation-server utf8mb4_unicode_ci 排序规则,兼容性好
我曾经接手过一个项目,数据库字符集用的latin1,结果用户昵称里带个表情符号就直接报错。后来全量迁移数据,折腾了两天。所以,一开始就设成utf8mb4,省心。

2.2 使用mysql2驱动连接数据库

MySQL装好了,接下来用Node.js连它。Node.js连MySQL的驱动有好几个,我推荐 mysql2。为什么?因为它支持Promise,性能也比老牌的mysql好一截。

2.2.1 安装mysql2

在项目目录下:

npm install mysql2

装完就能用了。先写个最简单的连接测试:

const mysql = require('mysql2');

const connection = mysql.createConnection({
  host: 'localhost',
  user: 'root',
  password: 'your_password',
  database: 'test'
});

connection.query('SELECT 1 + 1 AS result', (err, results) => {
  if (err) throw err;
  console.log('查询结果:', results[0].result);
});

connection.end();

跑一下,如果输出 查询结果: 2,说明连上了。

2.2.2 使用Promise风格

我个人习惯用Promise,代码更干净。mysql2支持两种方式:

const mysql = require('mysql2/promise');

async function testConnection() {
  const connection = await mysql.createConnection({
    host: 'localhost',
    user: 'root',
    password: 'your_password',
    database: 'test'
  });

  const [rows] = await connection.execute('SELECT 1 + 1 AS result');
  console.log('结果:', rows[0].result);

  await connection.end();
}

testConnection();

你看,用 async/await 之后,代码像同步一样清晰。而且 execute 方法默认会做参数化查询,防止SQL注入。这一点很重要,我在项目中见过太多直接拼接SQL的惨案。

小技巧:mysql2/promise 时,execute 返回的是一个数组,第一个元素是行数据,第二个是字段信息。如果你只想要行数据,用解构赋值 const [rows] = await connection.execute(...) 就行。

2.3 连接池配置与最佳实践

好,单个连接搞定了。但实际项目中,你不会每次请求都新建一个连接。那样太慢了,而且数据库扛不住。这时候就需要连接池。

连接池是什么?说白了,就是预先创建一批连接放在池子里。谁要用,从池子里拿一个;用完了,放回去。避免了反复创建销毁的开销。

2.3.1 创建连接池

mysql2创建连接池非常简单:

const mysql = require('mysql2/promise');

const pool = mysql.createPool({
  host: 'localhost',
  user: 'root',
  password: 'your_password',
  database: 'test',
  waitForConnections: true,
  connectionLimit: 10,
  queueLimit: 0
});

// 使用连接池查询
async function queryUsers() {
  const [rows] = await pool.execute('SELECT * FROM users WHERE id = ?', [1]);
  return rows;
}

这里有几个关键参数,我解释一下:

参数 说明 推荐值
connectionLimit 最大连接数 10-50,根据并发量调整
waitForConnections 连接用完时是否等待 true
queueLimit 等待队列最大长度,0表示不限制 0
idleTimeout 空闲连接超时时间(毫秒) 60000
maxIdle 最大空闲连接数 与connectionLimit相同

2.3.2 连接池的最佳实践

我在项目中踩过不少连接池的坑,总结几条经验:

  1. 连接数别设太大。 很多人觉得并发高就设个几百,结果数据库先挂了。我一般从10开始,压测后逐步上调。
  2. 一定要加超时。 设置 idleTimeoutconnectTimeout,防止连接泄漏。
  3. 用完就释放。 虽然连接池会自动回收,但最好显式调用 pool.releaseConnection(connection) 或直接用 pool.execute 这种自动管理的方式。
  4. 监控连接池状态。 可以用 pool.pool 查看当前活跃连接数、空闲连接数。

我曾经在一个高并发项目里,连接池设了100个,结果数据库CPU直接飙到100%。后来发现是某个慢查询占着连接不放,导致其他请求排队。最后把连接数降到20,优化了慢查询,问题才解决。所以,连接池不是越大越好,关键是要快。

2.3.3 封装一个数据库工具类

实际项目中,我习惯把连接池封装成一个模块,方便全局使用:

// 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 || 'test',
  waitForConnections: true,
  connectionLimit: 10,
  queueLimit: 0,
  enableKeepAlive: true,
  keepAliveInitialDelay: 0
});

module.exports = {
  query: async (sql, params) => {
    const [rows] = await pool.execute(sql, params);
    return rows;
  },
  getConnection: async () => {
    return await pool.getConnection();
  }
};

然后在业务代码里直接用:

const db = require('./db');

async function getUser(id) {
  return await db.query('SELECT * FROM users WHERE id = ?', [id]);
}

这样写的好处是,切换数据库或者调整连接池配置时,只需要改一个文件。

注意: 千万不要在每次请求时都创建新的连接池。连接池应该是单例的,全局只创建一次。否则连接数会爆炸,数据库直接挂掉。

2.4 本章小结

这一章我们做了三件事:装好MySQL、用mysql2连上它、配好连接池。嗯,看起来简单,但这些都是后面所有操作的基础。

我个人建议,你最好现在就打开终端,亲手装一遍MySQL,写一个连接测试脚本。光看不动手,永远记不住。下一章我们会讲ORM框架,到时候这些基础就派上用场了。

对了,如果你在安装或连接过程中遇到问题,别慌。检查一下MySQL服务是否启动、用户名密码是否正确、端口是否被占用。这些都是我当年踩过的坑,你大概率也会遇到。

避坑指南: 如果连接时报错 ER_NOT_SUPPORTED_AUTH_MODE,说明MySQL 8.0的认证插件不兼容。在MySQL里执行 ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY 'your_password'; 就能解决。