如何校验用户完成所有测试且不受试题增删操作影响
解决方案
核心思路是给用户每次测试参与行为独立建记录,快照存储参与当时的试题总量,和当次的答题数据绑定校验,完全隔离后续测试试题变动的影响。
表结构调整
- 新增
test_attempts(用户测试参与表),核心字段如下:CREATE TABLE test_attempts ( id INT PRIMARY KEY AUTO_INCREMENT, user_id INT NOT NULL, test_id INT NOT NULL, initial_question_count INT NOT NULL COMMENT '用户参与本次测试时,该套测试的总题数快照', started_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '本次参与开始时间', completed_at DATETIME DEFAULT NULL COMMENT '本次参与完成时间,为NULL代表未完成', UNIQUE KEY uniq_user_test_ongoing (user_id, test_id, completed_at) COMMENT '每个用户每套测试同时仅存在一个未完成的参与记录' ) - 原有
user_answers表新增attempt_id字段,关联test_attempts表的主键,用来标识当前答题属于哪一次测试参与。
业务逻辑调整
- 用户首次进入某套测试(不管是第一次考还是重考)时,优先查询是否存在该用户对应测试、
completed_at IS NULL的未完成参与记录:- 存在则直接复用该记录,读取
initial_question_count作为本次需要完成的总题数 - 不存在则新增一条参与记录,插入时实时查询当前
questions表中对应test_id的试题总条数,写入initial_question_count字段
- 存在则直接复用该记录,读取
- 用户每提交一道试题答案,写入
user_answers表后,统计当前attempt_id下已提交的去重question_id总条数 - 如果统计的已答题数等于本次参与的
initial_question_count,直接将对应test_attempts记录的completed_at设为当前时间,标记本次测试参与完成
完成校验逻辑
- 单套测试完成校验:判断对应用户、对应测试是否存在
completed_at IS NOT NULL的test_attempts记录即可,和当前测试的试题数量完全无关 - 重考资格校验:统计该用户所有测试的已完成参与记录数,和当前总测试套数对比,相等即可发起重考,重考时按上述逻辑生成新的
test_attempts记录即可
轻量替代方案(不想新增表的场景)
如果不想新增test_attempts表,可以给questions表加created_at和is_deleted软删除字段,所有试题永远不做物理删除;同时user_answers表新增attempt_id字段标识每次考试批次,每个批次的第一道题提交时记录下当前该测试所有非删除的试题ID集合存在额外字段,后续校验只要判断该批次用户已答的试题ID是否完全覆盖记录的ID集合即可。
该方案冗余度更高,维护成本也更高,更推荐新增参与表的方案。
内容的提问来源于stack exchange,提问作者user_411
相关产品推荐
相关产品推荐

