GORM默认仅当字段名为ID且类型为整型时自动启用主键+自增;若字段名非ID、类型非整型或含autoIncrement:false标签,则静默失效,需显式声明gorm:"primaryKey;autoIncrement"。

GORM 默认对 ID 字段启用主键 + 自增,但仅当类型是整数且未显式禁用时才生效;一旦字段名不是 ID、类型不是整型、或加了 autoIncrement:false 标签,就会静默失效——这是最常踩的坑。
gorm 主键自增依赖字段名、类型和标签三重条件
它不是“设了标签就生效”,而是先按惯例匹配,再被标签覆盖。默认行为是:
- 字段名为
ID(大小写敏感,Id或id都不行)且类型为整型(int,uint,int64等)→ 自动加primaryKey和autoIncrement - 字段名不是
ID→ 即使类型正确,也不会自动设自增,必须手动加gorm:"primaryKey;autoIncrement" - 类型是
string或uuid.UUID→autoIncrement会被忽略(数据库不支持字符串自增)
gorm v2 中 autoIncrement 标签的实际效果
这个标签只控制建表语句是否生成 AUTO_INCREMENT(MySQL)或 SERIAL(PostgreSQL),不参与运行时逻辑。常见误区:
-
autoIncrement:false不会阻止 GORM 在Create后读回 ID —— 只要数据库真有自增列,GORM 仍会LAST_INSERT_ID() - 如果表已存在且列没设自增,
AutoMigrate不会修改列属性,也不会报错,只会跳过 - SQLite 下
autoIncrement必须配合primaryKey才生效,单独写无效
不同数据库对自增的实际兼容性差异
同一段 struct 标签,在不同驱动下生成的 DDL 可能不同:
- MySQL:
gorm:"primaryKey;autoIncrement"→id BIGINT AUTO_INCREMENT PRIMARY KEY - PostgreSQL:
autoIncrement被映射为SERIAL类型(即INTEGER GENERATED ALWAYS AS IDENTITY),但要求字段类型是int或int64 - SQL Server:
autoIncrement对应IDENTITY(1,1),但需确保字段是int且无默认值 - SQLite:
INTEGER PRIMARY KEY自动具备 rowid 行为,autoIncrement标签仅在显式建表时起作用
手动指定主键自增字段的可靠写法
别依赖默认,显式声明最稳。例如想用 UserCode 当自增主键:
type User struct {
UserCode int `gorm:"primaryKey;autoIncrement"`
Name string
}
注意两点:
- 去掉
ID字段,否则 GORM 会同时尝试建两个主键,MySQL 报ERROR 1068 - 如果已有表结构,先确认数据库侧该列确实是自增列,否则
Create后UserCode会是 0
真正容易被忽略的是:迁移后务必用 db.Migrator().CurrentDatabase() == "mysql" 检查驱动类型,因为 autoIncrement 的底层实现完全由驱动决定,跨库移植时这里最容易出 silent failure。


















