求助开发随机不重复答题系统:MySQL记录已答题目逻辑实现
你的答题系统实现方案优化
首先,我得先指出你当前代码里的几个关键问题,这些问题会导致逻辑错误或者安全隐患:
现有代码的核心问题
- 随机数范围错误:你生成的是1-5的随机数,但你的题库有350道题,应该生成1-350的数
- 异步逻辑处理不当:
con.query是异步操作,但你用了同步的while循环,循环会在数据库查询完成前就执行,导致result的值无法正确判断 - SQL注入风险:直接把变量
x拼到SQL语句里,这是非常危险的做法,容易被注入攻击 - 循环条件逻辑错误:你初始化
result=0,然后循环条件是result >=1,这会导致循环根本不会执行 - 缺少总题数检查:没有先判断用户是否已经完成了350道题的逻辑
完整的实现方案
我会用Node.js的mysql2库(支持Promise和async/await,比原生mysql库更易维护)来实现,下面是完整的可运行代码:
第一步:安装依赖
先安装mysql2:
npm install mysql2
第二步:实现代码
const mysql = require('mysql2/promise'); // 创建数据库连接池(比单连接更适合高并发场景) const pool = mysql.createPool({ host: '你的数据库地址', user: '数据库用户名', password: '数据库密码', database: '数据库名' }); async function getQuizQuestions(userId) { try { // 1. 先检查用户已经完成的题目数量 const [countRows] = await pool.query( 'SELECT COUNT(*) AS total FROM users WHERE userid = ?', [userId] ); const totalCompleted = countRows[0].total; // 如果已经完成350道题,返回指定提示 if (totalCompleted >= 350) { return "you have completed the quiz"; } // 2. 获取用户已经答过的所有题号 const [existingQuestions] = await pool.query( 'SELECT question FROM users WHERE userid = ?', [userId] ); const existingIds = new Set(existingQuestions.map(row => row.question)); // 3. 生成5个不重复且未答过的随机题号 const newQuestionIds = []; while (newQuestionIds.length < 5) { // 生成1-350之间的随机整数 const randomId = Math.floor(Math.random() * 350) + 1; // 确保这个题号既没答过,也不在本次生成的列表里 if (!existingIds.has(randomId) && !newQuestionIds.includes(randomId)) { newQuestionIds.push(randomId); } } // 4. 将新题号插入数据库 const insertTasks = newQuestionIds.map(id => { return pool.query( 'INSERT INTO users (userid, question) VALUES (?, ?)', [userId, id] ); }); await Promise.all(insertTasks); // 返回本次的5道题题号(你可以根据实际需求改成返回题目内容) return newQuestionIds; } catch (error) { console.error('处理答题请求时出错:', error); throw error; // 或者根据业务需求处理错误 } } // 示例调用 getQuizQuestions('user_12345') .then(result => console.log('本次题目:', result)) .catch(err => console.error(err));
代码说明
- 连接池:使用连接池而不是单连接,能高效处理多个用户的并发请求,避免频繁创建销毁连接的开销
- Async/Await:用异步等待的方式编写代码,避免了回调地狱,逻辑更清晰易读
- 参数化查询:所有SQL语句都用
?作为占位符,然后传入参数数组,彻底避免SQL注入风险 - 高效去重:先用Set存储用户已答过的题号(Set的查找是O(1)时间复杂度),生成随机数时直接判断是否在Set里,比多次查询数据库高效得多
- 边界处理:先检查用户是否已经完成所有题目,提前返回提示,避免无效操作
可选优化建议
- 如果你的题库数量可能变化,可以从题目表中动态查询总题数,而不是硬编码350
- 可以把生成随机题号的逻辑封装成单独的工具函数,提高代码复用性
- 可以添加事务处理,确保5道题的插入要么全部成功,要么全部失败,避免数据不一致
内容的提问来源于stack exchange,提问作者Kern Elliott
相关产品推荐
相关产品推荐

