背景
第二天早上来的时候,发现接口返回异常Cannot enqueue Query after fatal error
从日志看上去,接口是正常运行的,搜索一下之后发现是数据库的问题,连接断开了
原因
MySQL中有一个名叫wait_timeout
的变量,表示操作超时时间,当连接超过一定时间没有活动后,会自动关闭该连接,这个值默认为28800(即8小时)
。对于这种普通连接的方式,在正式线上可能会遇到连接丢失的问题(No reconnection after connection lost
错误日志),连接丢失后不会自动重新连接,会触发error事件。
解决方案
我从网上尝试了好几种,有些自测不行,有些可以,我都列出来
- 连接配置中增加
useConnectionPooling: true
,这个我尝试了不行
let dbconfig = {
host: "db_host",
user: "db_user",
password: "db_pass",
database: "db_name",
useConnectionPooling: true,
debug: true,
};
- 捕获全局异常,判断code为
PROTOCOL_CONNECTION_LOST
,然后进行重启mysql,这个我也尝试了不行
process.on("uncaughtException", function (err) {
if (err.code == "PROTOCOL_CONNECTION_LOST") {
mysql.restart();
}
});
适用于还有另一个报错的情况,Error: Connection lost The server closed the connection
- 监听连接报错,然后重连,这个可以
function handleError(err) {
if (err) {
// 如果是连接断开,自动重新连接
if (err.code === "PROTOCOL_CONNECTION_LOST") {
connect();
} else {
console.error(err.stack || err);
}
}
}
// 连接数据库
function connect() {
db = mysql.createConnection(config);
db.connect(handleError);
db.on("error", handleError);
}
var db;
connect();
- 使用连接池的方式,每次查询完成之后释放连接池,这个也可行
var mysql = require("mysql");
var pool = mysql.createPool(config);
pool.getConnection(function (err, connection) {
connection.query("SELECT something FROM sometable", function (err, rows) {
connection.end();
});
});