Nodejs 操作 MySQL 出现 ER_LOCK_WAIT_TIMEOUT 问题

发布于 1周前 作者 nodeper 来自 nodejs/Nestjs

Nodejs 操作 MySQL 出现 ER_LOCK_WAIT_TIMEOUT 问题

操作 MySQL 用的 node-mysql

今早起来收到报告说用户无法登陆。我上服务器看了下进程是正常的,于是访问了下首页发现也没问题(首页就是一个静态页面,和数据库没交互) 于是我就尝试登陆下,发现确实无法登陆,点了登陆按钮后一直 loading,最后 timeout。

查了下日志,发现连续报了 2 同样的错:Error: ER_LOCK_WAIT_TIMEOUT: Lock wait timeout exceeded; try restarting transaction

这个错之后紧接着有 3 个连续的:Error: Handshake inactivity timeout

根据记录查询了下发现自从报了这错之后就再也没用户登陆了(应该就是这个错导致的了)

然后我接着连上数据库 SHOW PROCESSLIST,发现进程都正常

不知道从何下手,然后我重启了一下 node 进程就正常了

为什么出了死锁后会导致所有操作数据库的进程一直卡住啊?

这个业务线上跑了很久,第一次遇到这个问题。


3 回复

是用的这个吗?
https://github.com/mysqljs/mysql

如果排除确实是一些写数据库的 SQL 语句有问题导致锁表,可以试试我之前遇到过的不完美处理

按它的官方文档,一开始就 connection.connect(),然后用完调用 connection.end(); 发现报错,连不上数据库。
注释掉这两处就可以了。


谢谢你的回答。
用的就是这个,应该不是你这个原因。connection.end();是释放连接吧,和我的问题应该没关系。

遇到 Node.js 操作 MySQL 时出现的 ER_LOCK_WAIT_TIMEOUT 错误,通常意味着事务在尝试获取锁时等待时间超过了 MySQL 配置的锁等待超时时间。这个问题可能由多种原因引起,比如死锁、长时间运行的事务等。

首先,确保你的 MySQL 配置中的 innodb_lock_wait_timeout 设置合理。默认值通常是 50 秒,你可以根据需要调整:

SET GLOBAL innodb_lock_wait_timeout = 120;

然后,在 Node.js 应用中,你可以采取以下措施来避免或处理这个问题:

  1. 优化事务:确保事务尽可能短,只在必要时使用事务。

  2. 检查死锁:使用 SHOW ENGINE INNODB STATUS; 命令查看是否有死锁发生,并分析死锁的原因。

  3. 重试机制:在捕获到 ER_LOCK_WAIT_TIMEOUT 错误时,实现重试逻辑。

下面是一个简单的 Node.js 代码示例,展示了如何处理事务和重试机制:

const mysql = require('mysql');
const connection = mysql.createConnection({/* 配置信息 */});

function executeTransaction(callback) {
    connection.beginTransaction((err) => {
        if (err) {
            if (err.code === 'ER_LOCK_WAIT_TIMEOUT') {
                // 重试逻辑
                setTimeout(() => executeTransaction(callback), 1000);
            } else {
                callback(err);
            }
        } else {
            // 执行 SQL 操作
            connection.commit((err) => {
                if (err) callback(err);
                else callback(null);
            });
        }
    });
}

executeTransaction((err) => {
    if (err) console.error(err);
    else console.log('Transaction successful');
});

通过这种方式,你可以更好地处理 ER_LOCK_WAIT_TIMEOUT 错误。

回到顶部