不能直接删字段,必须用新建迁移执行 dropColumn();因 Laravel 迁移单向演进,修改已执行迁移无效且危险,需检查代码引用、备份数据、确认字段可弃用,并清理缓存。

不能直接删字段,必须用迁移回滚或新建迁移来删除——Laravel 的迁移是单向演进设计,php artisan migrate 只执行 up(),不支持在已有迁移里删字段再重跑。
为什么不能改已执行的迁移文件
修改已运行过的迁移(比如在 up() 里删掉一个 $table->string('old_field'))毫无作用:Laravel 不会重新解析旧迁移内容,也不会对比数据库结构反向生成 DDL。更危险的是,如果其他人本地已执行该迁移,你删了字段再 php artisan migrate,系统会跳过它(因 migrations 表已记录),字段依然存在;而你手动删库重迁又会丢数据。
正确做法:新建迁移执行 dropColumn
用 Artisan 命令生成新迁移,显式声明要删的字段:
php artisan make:migration drop_old_field_from_users_table --table=users
编辑生成的文件,在 up() 中调用 dropColumn():
public function up(MigrationBuilder $table)
{
Schema::table('users', function (Blueprint $table) {
$table->dropColumn('old_field'); // 支持传字符串或字符串数组
});
}
- MySQL 要求表引擎为 InnoDB(默认满足),否则会报错
SQLSTATE[HY000]: General error: 1843 Cannot change column 'xxx': used in a foreign key constraint - SQLite 不支持
dropColumn(),会直接抛出异常;必须用DB::statement()手动重建表,或换用 MySQL/PostgreSQL 开发环境 - PostgreSQL 需注意:若字段被索引、约束或视图依赖,
dropColumn()会失败,得先dropIndex()或dropForeign()
删字段前必须确认的三件事
删字段不是“写完 migrate 就跑”,容易引发线上事故:
- 检查代码中是否还有对这个字段的读写,包括模型的
$fillable、$casts、访问器、序列化逻辑 - 确认数据库备份已完成——
dropColumn是 DDL 操作,不可回滚(除非你有备份或 binlog) - 如果字段含重要业务数据(如
legacy_phone),先用php artisan tinker抽样查值,判断是否真可弃用
最常被忽略的是 SQLite 兼容性,以及没清空模型缓存导致 getAttribute() 仍返回 null 而不是报错——删字段后务必 php artisan config:clear && php artisan cache:clear,并检查 Eloquent 模型的 $hidden 和 $appends 是否误引用了已删字段。











