AWS Lambda二次调用mysql报错Cannot enqueue Query after invoking quit如何解决
问题根因
- 你将MySQL连接对象定义在全局作用域,AWS Lambda默认会复用冷启动生成的执行上下文,同一实例处理多次请求时会复用同一个全局连接对象。
- 第一次请求执行完毕后你调用了
connection.end()主动关闭了连接,该连接对象进入终止状态后,后续再调用connection.query()不会自动重建连接,因此触发报错。 connection.query的隐式建连逻辑仅适用于连接对象从未初始化过连接的场景,主动关闭后的连接对象不会触发自动重连。
推荐解决方案:使用连接池管理数据库连接
使用MySQL连接池替代单连接是Lambda场景下的最优选择,连接池会自动管理连接的创建、复用与销毁,无需手动调用end关闭连接,性能也远高于每次请求新建销毁单连接。
修改后的代码如下:
/* Amplify Params - DO NOT EDIT API_SIMPLETWITTERCLONE_GRAPHQLAPIENDPOINTOUTPUT API_SIMPLETWITTERCLONE_GRAPHQLAPIIDOUTPUT API_SIMPLETWITTERCLONE_GRAPHQLAPIKEYOUTPUT AUTH_SIMPLETWITTERCLONEB1022521_USERPOOLID ENV REGION Amplify Params - DO NOT EDIT */ const mysql = require("mysql"); const config = require("./config.json"); // 替换为创建连接池 const pool = mysql.createPool({ host: config.dbhost, user: config.dbuser, password: config.dbpassword, database: config.dbname, connectionLimit: 10, // 可根据实际场景调整,Lambda单实例并发不高的话设为1也可以 }); // resolvers const resolvers = { Query: { getAllUser: (event) => { return getAllUser(); }, }, }; function executeQuery(sql, params) { return new Promise((resolve, reject) => { const queryCallback = (error, results) => { if (error) { console.log("Error occured during query: " + error.message); reject(error); } else { console.log("Connected to database and executed query"); console.log("Results:", results); resolve(results); } }; // pool.query会自动获取连接、执行查询、释放连接,无需手动管理 if (params) { pool.query(sql, [...params], queryCallback); } else { pool.query(sql, queryCallback); } }); } async function getAllUser() { const sql = "SELECT * FROM User"; try { const users = await executeQuery(sql); return users; } catch (error) { throw error; } } exports.handler = async (event) => { console.log("event", event); const typeHandler = resolvers[event.typeName]; if (typeHandler) { const resolver = typeHandler[event.fieldName]; if (resolver) { return await resolver(event); } } throw new Error("Resolver not found"); };
可选低并发方案:每次请求新建单连接
如果你的接口请求量极低,也可以选择每次执行查询前新建连接,查询结束后销毁,修改逻辑如下:
- 移除全局的连接对象定义
- 在
executeQuery函数内部每次新建连接,执行完成后关闭
示例代码片段:
function executeQuery(sql, params) { return new Promise((resolve, reject) => { // 每次查询新建连接 const connection = mysql.createConnection({ host: config.dbhost, user: config.dbuser, password: config.dbpassword, database: config.dbname, }); const queryCallback = (error, results) => { if (error) { console.log("Error occured during query: " + error.message); connection.destroy(); reject(error); } else { console.log("Connected to database and executed query"); console.log("Results:", results); connection.end((err) => { if (err) console.log("there was an error closing database:" + err.message); resolve(results); }); } }; if (params) { connection.query(sql, [...params], queryCallback); } else { connection.query(sql, queryCallback); } }); }
注意事项
- 数据库的最大连接数需要大于Lambda的最大并发实例数,避免出现连接不足的报错
- 建议将Lambda的执行超时时间设置为小于数据库连接的超时时间,避免产生无效的僵尸连接
内容的提问来源于stack exchange,提问作者jmsandiegoo
相关产品推荐
相关产品推荐

