You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Laravel中如何避免随机获取试题时出现重复?

解决Laravel随机抽取试题避免重复的方案

咱先理清楚问题:你当前的代码每次从指定章节里随机捞1道题,但完全没记录用户已经见过哪些题,所以重复概率自然很高。要解决这个问题,核心思路就是跟踪用户已经浏览/作答过的试题ID,下次查询时直接排除这些ID。

下面给你两种常用的解决方案,按需选择:

一、基于Session的临时方案(适合未登录用户)

如果你的场景允许用户不登录做题,用Session来临时存储已做试题ID就足够了,简单快捷:

public function mcq($id) {
    // 从Session取出已做过的试题ID,默认是空数组
    $answeredIds = session()->get('answered_questions', []);
    
    // 查询当前章节下,用户没做过的试题,随机取1道
    $questions = Chapter::find($id)->questions()
        ->whereNotIn('id', $answeredIds)
        ->orderByRaw("RAND()")
        ->paginate(1);
    
    // 如果还有未做的题,把当前题ID加入已做列表,更新Session
    if ($questions->isNotEmpty()) {
        $answeredIds[] = $questions->first()->id;
        session()->put('answered_questions', $answeredIds);
    }
    
    return view('pages.mcq')->withQuestions($questions);
}

👉 优点:不需要额外改数据库,实现成本低;
👉 缺点:用户清除浏览器缓存、换设备的话,记录会丢失,适合临时刷题场景。

二、基于数据库的持久化方案(适合登录用户)

如果用户是登录状态,建议把答题记录存到数据库里,这样跨设备也能保留用户的答题进度:

第一步:创建关联表

先建一个user_answered_questions表,用来记录用户和已做试题的关联:

Schema::create('user_answered_questions', function (Blueprint $table) {
    $table->foreignId('user_id')->constrained()->onDelete('cascade');
    $table->foreignId('question_id')->constrained()->onDelete('cascade');
    $table->timestamps();
    $table->unique(['user_id', 'question_id']); // 防止重复记录同一道题
});

第二步:给User模型加关联

在User.php里添加和Question的多对多关联:

public function answeredQuestions() {
    return $this->belongsToMany(Question::class, 'user_answered_questions');
}

第三步:修改控制器代码

public function mcq($id) {
    // 获取当前登录用户
    $user = auth()->user();
    
    // 取出用户已做过的所有试题ID
    $answeredIds = $user->answeredQuestions()->pluck('questions.id')->toArray();
    
    // 查询章节下未做过的试题,随机取1道
    $questions = Chapter::find($id)->questions()
        ->whereNotIn('id', $answeredIds)
        ->orderByRaw("RAND()")
        ->paginate(1);
    
    // 如果有未做的题,把这道题记录到关联表
    if ($questions->isNotEmpty()) {
        $user->answeredQuestions()->attach($questions->first()->id);
    }
    
    return view('pages.mcq')->withQuestions($questions);
}

👉 优点:数据持久化,用户换设备也能接着上次的进度刷题;
👉 缺点:需要额外创建数据库表,适合有用户体系的正式项目。

边界情况处理

当章节里所有题都被用户做完之后,whereNotIn会返回空结果,这时候可以给用户加个提示,或者重置答题记录:

if ($questions->isEmpty()) {
    // 可选:重置答题记录(比如让用户重新刷)
    // session()->forget('answered_questions'); // Session方案的重置
    // $user->answeredQuestions()->detach(); // 数据库方案的重置
    
    return view('pages.mcq')->with('message', '该章节所有试题已全部完成!');
}

内容的提问来源于stack exchange,提问作者Hassan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 07:07:23