应清理重复数据后再迁移,对软删除表建复合唯一索引['email', 'deleted_at'],迁移类改用匿名类写法,TEXT字段需限定长度才能加unique,删索引须用规范名称。

迁移时提示“Duplicate entry for key xxx_unique”怎么办
直接报错说明表里已有重复数据,MySQL 建唯一索引前会全表校验,不清理就过不去。别试 IGNORE 或临时关约束——那只是掩盖问题,上线后照样出脏数据。
- 先查重复:
SELECT email, COUNT(*) FROM users GROUP BY email HAVING COUNT(*) > 1 - 手动清理或合并(比如保留最新一条,删其余;别用
TRUNCATE) - 清理完再跑
php artisan migrate,这是最稳路径 - 如果数据量大、不能停服,写个一次性 Artisan 命令做去重+迁移,别硬扛
软删除模型加 unique 索引容易漏掉 deleted_at
启用了 softDeletes() 的表,只对 email 加 unique(),会导致已软删的邮箱仍被锁住,新用户注册失败。这不是 bug,是设计使然——软删行还在表里,唯一索引照常生效。
- 正确做法是建复合唯一索引:
$table->unique(['email', 'deleted_at']) - 这样已删除用户的
deleted_at IS NOT NULL,和新用户deleted_at IS NULL就不冲突了 - 注意:
deleted_at字段必须允许为NULL,否则复合索引失效
迁移类名冲突导致“cannot declare class”错误
Laravel 9+ 官方推荐用匿名迁移,不是可选项,是解决类名冲突的唯一可靠方式。你删了旧文件但 Composer autoloader 还记着类名,或者两个迁移都叫 CreateUsersTable,PHP 就直接 fatal error。
- 把迁移文件里类似
class CreateUsersTable extends Migration整段删掉 - 换成 Laravel 官方写法:
return new class extends Migration { ... }; - 清 OPcache 和 Composer classmap:
opcache_reset()+composer dump-autoload - 别依赖
php artisan config:clear,它根本不管这事
unique() 和 index() 混用会白干活
很多人加了 $table->string('order_no')->index() 就以为“已经去重了”,结果上线发现订单号重复生成。index 只加速查询,不拦插入;unique 才是带约束的索引。
-
unique()自带索引效果,无需额外写index() - TEXT 字段不能直接
unique(),得先限定长度:$table->string('desc', 191)->unique() - 删唯一索引要用
$table->dropUnique('users_email_unique'),名字是固定格式,别手敲错
php artisan migrate 在本地都跑不通。这两处不提前踩坑,上线后比数据重复还难 debug。


















