Laravel迁移中id字段默认自增,非id字段需用bigIncrements()等方法;已有表加自增字段须先添加再用原生SQL设置;Eloquent需配合$incrementing和fillable确保正确插入。

在 Laravel 迁移中,id 字段默认就是自增主键,不需要额外设置;但如果你用的是非 id 字段、或需要手动控制自增行为(比如复合主键、UUID 替代、或旧表改造),就得小心处理——Laravel 的 increments() 和底层数据库的自增机制并不总是一一对应。
迁移中定义自增主键字段的正确写法
Laravel 提供了多个方法来声明自增字段,但它们适用场景和生成的 SQL 差异很大:
-
$table->id():Laravel 8+ 推荐方式,等价于$table->bigIncrements('id'),生成BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY -
$table->increments('id'):生成INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,已弃用(Laravel 8+ 警告,9+ 移除) -
$table->bigIncrements('order_no'):适用于非id字段的自增,如order_no,但需手动设为primary()或配合unique() -
$table->integer('sort')->autoIncrement():❌ 错误!autoIncrement()是无效链式调用,不会生成自增约束
关键点:只有 increments() / bigIncrements() 系列方法才会让 Laravel 在 CREATE TABLE 时写入 AUTO_INCREMENT;其他方式(如直接用 integer()->nullable(false))只是普通整数字段。
已有表添加自增字段的迁移陷阱
对已有数据表执行「添加自增字段」操作,不能只靠 $table->bigIncrements('new_id') —— 这会报错:SQLSTATE[HY000]: General error: 1833 Cannot change column 'new_id': used in a foreign key constraint 或更常见的 Cannot add auto-increment column without primary key。
- 必须先加字段(不带自增),再用
DB::statement()手动执行原生 SQL 设置自增 + 主键 - 如果表已有数据,需先确保该字段值唯一且非空,否则
ALTER TABLE ... MODIFY ... AUTO_INCREMENT会失败 - MySQL 8.0+ 对
AUTO_INCREMENT列要求必须是索引的一部分(通常是PRIMARY KEY或UNIQUE),所以得同步加索引
Schema::table('users', function (Blueprint $table) {
$table->unsignedBigInteger('legacy_id')->nullable()->after('id');
});
// 再执行一次迁移(或用 DB::statement 在同一迁移中)
DB::statement('ALTER TABLE users MODIFY legacy_id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY FIRST');
自增字段与 Eloquent 模型的配合要点
即使数据库字段是自增的,Eloquent 仍可能因配置问题跳过自动赋值:
- 模型中若定义了
protected $primaryKey = 'order_no',但没设public $incrementing = true(默认为true),则save()时不会尝试生成新值 - 若字段名不是
id,且类型不是BIGINT或INT(比如用了CHAR(36)),incrementing = true也无意义——自增是数据库行为,不是 PHP 生成的 - 使用
DB::table('xxx')->insert([...])时,自增由数据库触发,无需传值;但用Model::create()时,若字段不在$fillable中,会被忽略,导致插入NULL报错(尤其当字段设了NOT NULL但没AUTO_INCREMENT)
真正容易被忽略的是:自增逻辑完全由数据库引擎控制,Laravel 迁移只是帮你发一条 CREATE TABLE ... AUTO_INCREMENT 语句;一旦表结构建好,后续插入是否自增、起始值是多少、是否重用删除后的 ID,全看 MySQL/PostgreSQL 的配置和当前表状态,跟 Laravel 无关。









