Express后端执行MySQL查询遇TypeError,求问题排查及错误处理方案
问题:Express中MySQL查询出现TypeError: Cannot read properties of undefined (reading 'word')
我在Express服务器中执行MySQL查询时遇到错误,负责生成每日单词组合的generateDailyWords函数代码如下:
module.exports.generateDailyWords = async function () { try { // generate the shape of word combination for the day var shape = generateRandomNumbers(); // retrieve 4 words from the dictionary var q_1 = ` SELECT word FROM new_dic WHERE LENGTH(word) = ? ORDER BY RAND() LIMIT 1 `; var first = await excuteQuery(q_1, [shape[0]]); var word_1 = first[0].word; var q_2 = ` SELECT word FROM new_dic WHERE LENGTH(word) = ? AND word LIKE ? AND word != ? ORDER BY RAND() LIMIT 1 `; var second = await excuteQuery(q_2, [shape[1], word_1[0] + "%", word_1]); var word_2 = second[0].word; var q_3 = ` SELECT word FROM new_dic WHERE LENGTH(word) = ? AND word LIKE ? AND word != ? AND word != ? ORDER BY RAND() LIMIT 1 `; var third = await excuteQuery(q_3, [ shape[1], word_1[word_1.length - 1] + "%", word_1, word_2, ]); var word_3 = third[0].word; var q_4 = ` SELECT word FROM new_dic WHERE LENGTH(word) = ? AND word LIKE ? AND word != ? AND word != ? AND word != ? ORDER BY RAND() LIMIT 1 `; var forth = await excuteQuery(q_4, [ shape[0], word_2[word_2.length - 1] + "%" + word_3[word_3.length - 1], word_1, word_2, word_3, ]); var word_4 = forth[0].word; // save the combination into the database var combination = JSON.stringify([word_1, word_2, word_3, word_4]); return combination; // return '["jube","juicy","ender","ywar"]' } catch (err) { console.log(err, "err while generating daily words"); await this.generateDailyWords(); } };
该函数定期运行(测试阶段每10分钟一次,正式环境改为每日一次),但有时会抛出错误:
TypeError: Cannot read properties of undefined (reading 'word')
打印查询返回的数据后发现,有时查询结果变量为undefined。我需要了解问题原因,以及后端错误处理的最佳实践(比如编写错误处理辅助函数的方法)。
问题原因
- 查询无匹配结果:当
executeQuery执行后返回的结果数组为空时,first[0]、second[0]等取值会是undefined,此时访问.word属性就会触发TypeError。比如:shape生成的单词长度在字典表new_dic中没有对应数据;- 后续查询的过滤条件(比如
LIKE前缀、排除已选单词)过于严格,没有符合条件的单词。
- 无限制递归重试风险:当前catch块中直接递归调用
generateDailyWords,如果连续多次查询无结果,会导致调用栈溢出,引发更严重的错误。
修复方案
1. 每次查询后校验结果+限制重试次数
在提取word属性前先检查查询结果,同时给重试逻辑加次数限制,避免栈溢出:
module.exports.generateDailyWords = async function (retryCount = 0) { const MAX_RETRIES = 5; // 限制最大重试次数 try { const shape = generateRandomNumbers(); // 封装查询单个单词的校验逻辑 async function getWord(query, params) { const result = await excuteQuery(query, params); if (!result || result.length === 0) { throw new Error(`No matching word found for params: ${JSON.stringify(params)}`); } return result[0].word; } const word_1 = await getWord(` SELECT word FROM new_dic WHERE LENGTH(word) = ? ORDER BY RAND() LIMIT 1 `, [shape[0]]); const word_2 = await getWord(` SELECT word FROM new_dic WHERE LENGTH(word) = ? AND word LIKE ? AND word != ? ORDER BY RAND() LIMIT 1 `, [shape[1], `${word_1[0]}%`, word_1]); const word_3 = await getWord(` SELECT word FROM new_dic WHERE LENGTH(word) = ? AND word LIKE ? AND word != ? AND word != ? ORDER BY RAND() LIMIT 1 `, [shape[1], `${word_1[word_1.length - 1]}%`, word_1, word_2]); const word_4 = await getWord(` SELECT word FROM new_dic WHERE LENGTH(word) = ? AND word LIKE ? AND word != ? AND word != ? AND word != ? ORDER BY RAND() LIMIT 1 `, [shape[0], `${word_2[word_2.length - 1]}%${word_3[word_3.length - 1]}`, word_1, word_2, word_3]); const combination = JSON.stringify([word_1, word_2, word_3, word_4]); return combination; } catch (err) { console.error(`[Retry ${retryCount}] Error generating daily words:`, err.message); // 达到最大重试次数则抛出错误,避免栈溢出 if (retryCount >= MAX_RETRIES) { throw new Error(`Failed to generate daily words after ${MAX_RETRIES} retries: ${err.message}`); } // 递归重试,次数+1 return await this.generateDailyWords(retryCount + 1); } };
2. 优化查询条件(可选)
- 提前校验
shape生成的长度是否在字典中有对应数据,避免无效查询; - 对于
LIKE条件,如果前缀匹配无结果,可以放宽条件(比如改为包含该字符,或者直接随机选同长度单词)。
后端错误处理最佳实践
1. 封装通用查询辅助函数
把查询、结果校验的逻辑封装成复用函数,减少重复代码,统一错误处理:
async function executeSafeQuery(query, params, errorMessage = "Query failed") { try { const result = await excuteQuery(query, params); if (!result || result.length === 0) { throw new Error(`${errorMessage}: No results returned`); } return result; } catch (err) { console.error(`Database query error:`, err); throw new Error(`${errorMessage}: ${err.message}`); } } // 使用示例 const firstResult = await executeSafeQuery(q_1, [shape[0]], "Failed to get first word"); const word_1 = firstResult[0].word;
2. 限制重试次数
避免无限制递归,设置最大重试阈值,超过后抛出明确错误,便于监控和排查。
3. 详细日志记录
记录错误时包含查询参数、重试次数、错误栈等信息,方便定位问题根源。
4. 区分错误类型
自定义错误类,区分不同场景的错误(比如数据库连接错误、无结果错误、参数错误等),便于针对性处理:
class NoResultsError extends Error { constructor(message) { super(message); this.name = "NoResultsError"; } } // 在getWord函数中抛出 if (!result || result.length === 0) { throw new NoResultsError(`No word found for params: ${JSON.stringify(params)}`); }
5. 避免静默失败
不要在catch块中只打印日志而不处理错误,确保错误能被上层调用者捕获,或者触发告警机制。
内容的提问来源于stack exchange,提问作者Nikola Maksimovic
相关产品推荐
相关产品推荐

