Node.js 连接操作 MySQL
一、Node.js 连接 MySQL
1、简单示例
初始化项目:
npm init -y
安装 MySQL2:
npm install --save mysql2
新建 index.js
:
index.js
// 导入模块
const mysql = require('mysql2');
// 创建一个数据库连接
const connection = mysql.createConnection({
// 以下为建立的连接详情
host: 'localhost',
user: 'root',
password: 'xxx',
port: 3306,
database: 'myblog'
});
// 简单查询
connection.query(
'SELECT * FROM users',
function (err, res) {
if (err) throw error
console.log(res); // 结果集
}
);
// 关闭连接
connection.end();
运行:
node index.js
打印结果:
2、连接选项
createConnection 可以设置以下选项:
选项 | 说明 | 默认值 |
---|---|---|
host | 要连接的数据库主机名 | localhost |
port | 主机端口号 | 3306 |
localAddress | 用于 TCP 连接的 IP 地址 | 可选 |
socketPath | 链接到 unix 域的路径,在使用 host 和 port 时会被忽略 | 可选 |
user | MySQL 用户名 | - |
password | MySQL 密码 | - |
database | 链接到的数据库名 | 可选 |
charset | 连接的字符集 | UTF8_GENERAL_CI |
timezone | MySQL 服务器上配置的时区 | local |
connectTimeout | 连接超时时间,单位毫秒 | 10000 |
stringifyObjects | 是否序列化(字符串化)对象 | false |
insecureAuth | 是否允许旧的身份验证方法连接到数据库实例 | false |
typeCast | 是否将 column 值转为本地 JS 类型列值 | true |
queryFormat | 自定义的查询语句格式化函数,点击查看自定义格式 | - |
supportBigNumbers | 数据库处理大数字(BIGINT 和 DECIMAL)时启用 | false |
bigNumberStrings | 启用 supportBigNumbers 和 bigNumberStrings 强制大数字(BIGINT 和 DECIMAL)始终以字符串返回 | false |
dateStrings | 强制日期类型(TIMESTAMP、DATETIME、DATE)作为字符串返回,而非 JS Date 对象 | false |
debug | 是否开启调试 | false |
trace | 生成堆栈跟踪 Error 以包括库入口的调用站点(“长堆栈跟踪”) | true |
multipleStatements | 每个查询允许多个 MySQL 语句 | false |
flags | 链接标志 | - |
ssl | 带有 ssl 参数的对象或包含 ssl 配置文件名的字符串 | - |
3、建立连接
建立连接的推荐方法:
const mysql = require('mysql');
const connection = mysql.createConnection({
host: 'example.org',
user: 'xxx',
password: 'xxx'
});
connection.connect(function (err) {
if (err) {
console.error('error connecting: ' + err.stack);
return;
}
console.log('connected as id ' + connection.threadId);
});
也可以通过 query
调用查询来隐式建立连接 ▼
4、query API
4-1、基本用法
.query(sqlString, callback)
参数:
- sqlString:SQL 语句;
- callback:回调,参数如下 ▼
error
:如果语句执行期间发生错误,则存储详细错误;results
:包含查询的结果;fields
:包含结果字段信息。
示例:
const mysql = require('mysql');
const connection = mysql.createConnection({
host: 'example.org',
user: 'xxx',
password: 'xxx'
});
connection.query(`SELECT * FROM users WHERE username = 'aaa'`, function (error, results, fields) {
if (error) throw error;
// ...
});
4-2、使用占位符
.query(sqlString, values, callback)
使用单个占位符:
connection.query(`SELECT * FROM users WHERE username = ?`, ['aaa'], function (error, results, fields) {
if (error) throw error;
// ...
});
使用多个占位符:
connection.query(`SELECT * FROM users WHERE username = ? AND password = ?`, ['aaa', 111], function (error, results, fields) {
if (error) throw error;
// ...
});
与 connection.escape() 的方式一样,可以避免 SQL 注入攻击。
注意
语句所有 ?
都会被替换,包括注释和字符串中包含的语句。不同的值类型会以不同方式进行转义,例如:
- 数字保持不变;
- 布尔值转换为
true
/false
- 日期对象将转换为
'YYYY-mm-dd HH:ii:ss'
字符串; - 缓冲区转换为十六进制字符串,例如
X'0fa5'
- 字符串安全地逃脱;
- 数组变成列表,例如
['a', 'b']
变成'a', 'b'
- 嵌套数组被转换为分组列表(对于批量插入),例如
[['a', 'b'], ['c', 'd']]
变成('a', 'b'), ('c', 'd')
- 具有
toSqlString
方法的对象将.toSqlString()
被调用,并且返回的值将用作原始 SQL; - 对象被转换为对象上
key = 'val'
每个可枚举属性的对。如果属性的值是函数,则跳过它; 如果属性的值是一个对象,则在其上调用toString()
并使用返回的值; undefined
/null
转换为NULL
NaN
/Infinity
保持原样,MySQL 不支持并且会报错。
4-3、使用高级选项
.query(options, callback)
示例:
connection.query({
sql: 'SELECT * FROM `books` WHERE `author` = ?',
timeout: 40000, // 40s
values: ['David']
}, function (error, results, fields) {
// ...
});
5、关闭连接
关闭数据库连接有两种方法。
end()
方法确保在数据库连接关闭前始终执行所有剩余的查询:
conn.end(function (err) {
// 处理回调
});
如果要立即强制连接,可以使用 destroy()
方法,它保证不再为连接触发回调或事件:
// 没有回调
conn.destroy()
6、连接池
数据库连接池负责分配、管理和释放数据库连接,它允许应用程序重复使用一个现有的数据库连接,而不是再重新建立一个;换句话说,就是通过重用以前的连接来减少连接到 MySQL 服务器的时间。
创建连接池如下:
// 导入模块
const mysql = require('mysql2');
// 创建连接池,设置连接池的参数
const pool = mysql.createPool({
host: 'localhost',
user: 'root',
database: 'test',
waitForConnections: true,
connectionLimit: 10,
queueLimit: 0
});
该池不会预先创建所有连接,而是根据需要创建它们,直到达到连接限制。
可以像直接连接一样使用池:
pool.query('SELECT * FROM users;', function (err, results, fields) {
if (err) {
// 异常处理
throw err;
} else {
// 处理查询数据
console.log(results);
}
});
要从池中获取连接,可以使用 getConnection()
方法:
pool.getConnection(function (err, connection) {
// execute query
// ...
});
要在完成连接后将其连接到池,可以调用 connection.release()
:
// 使用连接
pool.getConnection(function (err, connection) {
connection.query('SELECT * FROM users;', function (err, results, fields) {
// 完成连接后,将其释放
connection.release();
// 不要在这里使用连接,它已经返回到池中
if (err) {
throw err;
} else {
console.log(results);
}
});
});
二、Node.js 操作 MySQL
1、创建 MySQL 表
创建一个名为 users
的表:
// 连接数据库
connection.connect(function (err) {
if (err) {
return console.error('error: ' + err.message);
}
const createToDos = `CREATE TABLE
IF
NOT EXISTS users (
id INT PRIMARY KEY auto_increment,
username VARCHAR ( 20 ) NOT NULL,
password varchar ( 20 ) NOT NULL
)`;
connection.query(createToDos, function (err, results, fields) {
if (err) {
throw err;
}
});
connection.end(function (err) {
if (err) {
return console.log(err.message);
}
});
});
创建的表结构如下:
表数据如下:
2、表数据插入(增)
2-1、插入一条数据
const sql = `INSERT INTO users (username, password)
VALUES ('aaa', 111)`;
connection.query(sql);
connection.end();
执行结果:
2-2、占位符插入并返回 ID
const sql = `INSERT INTO users (username, password)
VALUES (?, ?)`;
const val = ['bbb', 222];
connection.query(sql, val, (err, results, fields) => {
if (err) {
throw err;
}
console.log(results)
console.log('Id: ' + results.insertId);
});
connection.end();
执行结果:
控制台打印结果:
2-3、插入多条数据
const sql = `INSERT INTO users (username, password)
VALUES ?`;
const val = [
['ccc', 333],
['ddd', 444],
['eee', 555]
];
connection.query(sql, [val], (err, results, fields) => {
// ...
});
connection.end();
执行结果:
3、表数据删除(删)
const sql = `DELETE FROM users
WHERE id = ?`;
// 清除 ID 为 1 的数据
connection.query(sql, 1, (err, results, fields) => {
// ...
});
connection.end();
执行结果:
同理可以用数组实现多条数据的删除。
4、表数据更改(改)
const sql = `UPDATE users
SET username = 'xxx'
WHERE id = ?`;
// 修改 ID 为 2 的数据
connection.query(sql, 2, (err, results, fields) => {
// ...
});
connection.end();
执行结果:
5、表数据查询(查)
写法参照上面 query API
示例:
const sql = `SELECT * FROM users
WHERE id = ?`;
// 查找 ID 为 2 的数据
connection.query(sql, 2, (err, results, fields) => {
if (err) {
throw err;
}
console.log(results)
});
connection.end();
打印输出: