Laravel自定义忘记密码报错SQLSTATE[23000]:主键重复
解决Laravel自定义忘记密码时的SQL重复主键错误
错误原因
你遇到的SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry 'example@gmail.com' for key 'PRIMARY'错误,根源是**password_resets表将email字段单独设为了主键**。
Laravel默认的密码重置逻辑中,同一邮箱可多次请求重置链接:每次请求时会先删除该邮箱已有的旧重置记录,再插入新的token。但如果email是唯一主键,当该邮箱已有重置记录时,新的插入操作会触发主键唯一性约束,导致报错。
解决方案
方案1:修正表结构(推荐,符合Laravel默认设计)
移除email的单独主键,改为设置email和token的联合主键,这样同一邮箱可对应多个token(Laravel会自动清理旧记录):
- 创建新的迁移文件:
php artisan make:migration fix_password_resets_table - 在生成的迁移文件中编写结构修改逻辑:
use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; return new class extends Migration { public function up() { Schema::table('password_resets', function (Blueprint $table) { // 移除原有的email主键 $table->dropPrimary('email'); // 设置email和token为联合主键 $table->primary(['email', 'token']); }); } public function down() { Schema::table('password_resets', function (Blueprint $table) { $table->dropPrimary(['email', 'token']); $table->primary('email'); }); } }; - 执行迁移生效:
php artisan migrate
方案2:在自定义逻辑中先删除旧记录(不修改表结构时用)
如果不想调整表结构,需确保每次生成新重置token前,先删除该邮箱的旧记录:
在你的ForgotPasswordController的重置链接发送方法中,添加删除逻辑:
use Illuminate\Support\Facades\DB; // 示例:在处理请求的方法中 public function sendResetLinkEmail(Request $request) { // 验证请求参数... // 先删除该邮箱已有的重置记录 DB::table('password_resets')->where('email', $request->email)->delete(); // 然后执行生成token、发送邮件的逻辑... }
额外检查
如果你的自定义控制器重写了Laravel默认的密码重置逻辑,确认是否遗漏了PasswordBroker中默认的deleteExistingTokens方法调用——这个方法负责清理旧记录,是避免重复插入的关键。
内容的提问来源于stack exchange,提问作者Leo
相关产品推荐
相关产品推荐

