Node.js中如何将现有SQL查询替换为SELECT FOR UPDATE?
使用SELECT FOR UPDATE优化你的Node.js MySQL查询
首先,SELECT FOR UPDATE的作用是锁定查询到的行,确保在当前事务完成(提交或回滚)之前,其他事务无法修改这些行,这在处理并发场景(比如用户余额更新、订单状态修改)时非常有用。不过要注意,必须配合事务使用,否则锁会在查询执行完成后立即释放,起不到预期效果。
下面是修改后的完整代码,我会标注关键改动点:
pool.connect((err, db) => { if(err) { console.log("Failed connection to mysql"); errHandler(err); return; } // 1. 开启事务 db.beginTransaction((err) => { if (err) { console.log("Failed to start transaction"); errHandler(err); db.release(); // 释放连接 return; } // 2. 修改SQL语句,添加FOR UPDATE let sql1 = 'select * from user where email = ? and role_number = ? FOR UPDATE'; db.query(sql1, [email, role], (err, result) => { if(err) { console.log("Error in checking existing email"); // 出错时回滚事务 db.rollback(() => { errHandler(err); db.release(); // 释放连接 }); return; } // 这里可以添加你需要执行的后续操作(比如更新用户信息、修改关联表数据等) // 示例:更新用户的last_login时间 let updateSql = 'UPDATE user SET last_login = NOW() WHERE email = ?'; db.query(updateSql, [email], (err, updateResult) => { if (err) { console.log("Error updating user"); db.rollback(() => { errHandler(err); db.release(); }); return; } // 3. 所有操作完成后提交事务 db.commit((err) => { if (err) { db.rollback(() => { console.log("Failed to commit transaction"); errHandler(err); db.release(); }); return; } console.log("Transaction completed successfully"); db.release(); // 最后一定要释放连接 }); }); }); }); });
关键注意事项:
- 存储引擎要求:你的
user表必须使用InnoDB存储引擎(MyISAM不支持事务和行级锁),否则SELECT FOR UPDATE不会生效。 - 连接释放:无论操作成功还是失败,都要记得调用
db.release()释放连接回连接池,避免连接泄漏。 - 死锁预防:尽量减少事务的执行时间,避免长时间持有锁;同时确保多个事务的锁获取顺序一致,防止死锁。
- 隔离级别:MySQL默认的隔离级别是
REPEATABLE READ,这已经能满足大部分使用SELECT FOR UPDATE的场景,如果有特殊需求可以调整。
内容的提问来源于stack exchange,提问作者heyitsvajid
相关产品推荐
相关产品推荐

