Laravel 8迁移报错errno:150「外键约束格式错误」问题求助
Laravel 8迁移报错errno:150「外键约束格式错误」问题求助
兄弟,我之前也踩过这个外键约束的坑!咱们先一步步拆解问题,看看哪里出了问题。
首先,你遇到的errno:150错误,在Laravel迁移里最常见的原因无非这几个:
- 关联字段的数据类型/长度完全不匹配
- 父表(也就是你的
products表)的关联字段不是主键或未建立索引 - 两张表的存储引擎不一致(只有InnoDB支持外键,MyISAM不行)
- 迁移文件执行顺序颠倒(不过你已经确认
products表先创建,这条可以排除)
咱们再对照你的代码来看:
你的products表用了$table->id(),这个方法在Laravel里等价于$table->bigIncrements('id'),也就是无符号BIGINT类型的主键。而你在product_exchanges里写的是$table->bigInteger('product_id')->unsigned(),看起来类型是匹配的,但可能是写法不规范或者引擎的问题导致报错。
给你两个靠谱的解决方案:
方案一:用Laravel官方推荐的外键语法(最省心)
直接替换product_exchanges表中product_id字段的代码,Laravel的foreignId()方法会自动帮你创建匹配类型的字段,还能一键关联父表:
Schema::create('product_exchanges', function (Blueprint $table) { $table->id(); $table->dateTime('date'); $table->double('amount')->unsigned(); $table->integer('count_from')->unsigned(); $table->integer('count_to')->unsigned(); // 替换成这一行,自动关联products表的id,同时支持级联更新删除 $table->foreignId('product_id')->constrained('products')->onUpdate('cascade')->onDelete('cascade'); $table->timestamps(); });
方案二:手动指定字段类型+统一存储引擎
如果想保持手动写法,需要确保两点:
- 外键字段用
unsignedBigInteger和父表的bigIncrements完全匹配 - 两张表都明确指定InnoDB引擎(避免数据库默认引擎是MyISAM)
修改后的products表迁移:
Schema::create('products', function (Blueprint $table) { $table->engine = 'InnoDB'; // 强制指定引擎 $table->id(); $table->text('name'); $table->boolean('active')->default(1); $table->timestamps(); });
修改后的product_exchanges表迁移:
Schema::create('product_exchanges', function (Blueprint $table) { $table->engine = 'InnoDB'; // 强制指定引擎 $table->id(); $table->dateTime('date'); $table->double('amount')->unsigned(); $table->integer('count_from')->unsigned(); $table->integer('count_to')->unsigned(); $table->unsignedBigInteger('product_id'); // 用unsignedBigInteger匹配父表的bigIncrements $table->foreign('product_id')->references('id')->on('products')->onUpdate('cascade')->onDelete('cascade'); $table->timestamps(); });
最后提醒一句:如果之前已经执行过迁移,记得先执行php artisan migrate:rollback回滚旧结构,再重新执行迁移php artisan migrate,避免旧表结构残留导致报错哦!
备注:内容来源于stack exchange,提问作者Moamen Ali
相关产品推荐
相关产品推荐

