Laravel生产服务器执行database migration的正确操作方法
Laravel生产环境执行数据库Migration的标准方案
Laravel的Migration体系本身就是为跨环境增量同步表结构设计的,按规范编写的迁移文件,在生产环境执行不会丢失数据,也不会出现重复建表报错。你碰到的问题本质是开发阶段的迁移编写习惯不符合框架设计逻辑,加上误用了仅适合本地环境的操作命令导致的。
一、从开发端规范Migration写法,从根源避免生产报错
- 永远不要修改已经执行过的迁移文件,哪怕只是本地跑过一次、还没上线的也不行。所有表结构调整——不管是加字段、改字段属性、加索引、删字段,都必须生成全新的独立迁移文件,绝对不要为了省事直接改最早的建表迁移。
举个例子:你已经有2024_01_01_000000_create_users_table.php这个建表文件,现在需要给users表加avatar字段,不要直接在Schema::create的回调里加字段定义,而是先执行命令生成独立的变更迁移:
在新生成的迁移文件里,用php artisan make:migration add_avatar_to_users_table --table=usersSchema::table()方法写结构变更逻辑,同时写好对应的回滚逻辑:public function up() { Schema::table('users', function (Blueprint $table) { $table->string('avatar')->nullable()->after('email'); }); } public function down() { Schema::table('users', function (Blueprint $table) { $table->dropColumn('avatar'); }); } - 本地开发阶段可以随便用
php artisan migrate:refresh --seed重建表灌测试数据,这个命令天生就是给本地测试环境设计的,永远不要在生产环境跑refresh/fresh/reset这三个命令——这三个命令的核心逻辑就是删除所有表再重建,执行就会丢全量生产数据。 - 所有迁移必须写完整可执行的
down()回滚逻辑,避免上线执行出错后无法快速回退。 - 提交代码前本地可以多跑一轮
migrate->rollback->migrate的流程,确认up、down逻辑都没有语法错误,不会出现执行到一半失败的问题。
二、已经出现「table already exists」报错的修复方式
如果你之前已经改了旧的建表迁移,导致生产/其他协同环境跑迁移时报这个错,按下面的步骤修复即可,不需要手动改表:
- 把所有被修改过的旧建表迁移,恢复到它第一次被执行时的原始状态,把你后来加的字段、索引等结构调整逻辑,全部拆分到独立的新变更迁移里
- 核对生产数据库的
migrations表,确认所有已经记录在案的迁移,都和代码仓库里的对应文件内容完全一致,没有被篡改 - 不要手动删生产的业务表,也不要清空
migrations表的记录,修复完迁移文件后直接执行php artisan migrate,框架会自动跳过所有已经执行过的旧迁移,只跑新增的变更迁移,不会触发重复建表逻辑。
三、生产环境执行Migration的标准上线流程
每次代码发布上线后,按以下步骤执行结构更新,全程不会影响已有业务数据:
- 上线前先全量备份生产数据库,这是必做的兜底操作,哪怕迁移逻辑写漏了也能快速回滚恢复
- 涉及核心业务、大表变更的场景,可以先切维护模式避免用户访问时碰到结构变更的中间态:
php artisan down - 直接执行
php artisan migrate,不要加任何额外参数,这个命令是增量执行逻辑,只会跑之前没执行过的新迁移,不会修改、删除已有的表和存量数据 - 如果有需要在生产执行的填充(比如系统基础配置、字典类的固定数据),单独指定对应的Seeder类执行,比如
php artisan db:seed --class=SystemConfigSeeder,绝对不要在生产跑不带--class参数的全量db:seed,避免把本地测试用的假数据灌到生产库 - 结构更新完成后关闭维护模式:
php artisan up
四、高频注意事项
- 不要直接在生产数据库手动加字段、改索引,你手动做的结构变更不会有迁移记录,后续其他环境部署、新同事搭本地环境都会出现表结构不一致的问题,后续迁移逻辑引用到这些手动加的字段时也容易触发报错。
- 百万级以上大表加字段、加索引的场景,不要直接用Laravel默认的Schema方法操作,会触发全表锁导致线上服务中断,可以把无锁变更的SQL逻辑写在迁移里,或者配合在线DDL工具执行。
- 不要把测试用的Seeder和生产需要的基础数据Seeder混写,避免误执行污染生产数据。
内容的提问来源于stack exchange,提问作者Leonardo Sasso
相关产品推荐
相关产品推荐

