gorm:"default:xxx"仅在Create()插入时生效,会跳过Go零值字段让数据库填充默认值;Save()/Update()不触发该逻辑,传零值将直接写入数据库。

gorm:"default:xxx" 只在插入时生效,且会覆盖 Go 零值
Go 结构体字段默认是零值(0、""、false),GORM 不会自动跳过这些值去用数据库默认值——除非你显式声明 default tag。一旦加了 gorm:"default:18",只要字段值是 0(比如 Age int 未赋值),GORM 就会在 INSERT SQL 中省略该字段,让数据库用 DEFAULT 18 填充。
注意:这个行为只作用于 Create(),Save() 和 Update() 不触发默认值逻辑;更新时传了 0,就会真把 0 写进数据库。
-
default是数据库级默认值,不是 Go 层面的初始化逻辑 - 字符串默认值要带引号写进 tag:
gorm:"default:'张三'",否则 MySQL 会报语法错 - 时间类型慎用
default,推荐用autoCreateTime/autoUpdateTime更可靠
gorm:"not null" 不等于“不传字段”,而是强制数据库校验
加了 gorm:"not null",GORM 会在建表时加 NOT NULL 约束,但不会阻止你传一个 "" 或 0 进去——它只是把校验交给数据库。如果结构体字段是 string 且没赋值,Go 给的是 "",GORM 仍会把它当有效值插入,结果被数据库拦住并报错:ERROR: null value in column "name" violates not-null constraint(PostgreSQL)或类似 MySQL 的 Column 'name' cannot be null。
- 想避免零值误插,得配合指针类型(如
*string)或自定义 setter 方法 -
not null和default可共存,但语义上冲突:有默认值就无需非空;真要非空,应确保业务层不传零值 - MySQL 中
NOT NULL字段若没设DEFAULT,又收到NULL,直接报错;而 GORM 默认不发NULL,发的是零值,所以实际触发报错的往往是零值本身
别混淆 gorm:"default" 和 Go struct 字段初始值
写 Name string = "李四" 这类 Go 层默认值,对 GORM 没任何影响。GORM 只认 gorm:"default:..." tag。更危险的是:如果你同时写了 Go 初始值和 gorm:"default",而字段又是非指针类型,那 Go 初始值会先覆盖结构体零值,导致 default tag 完全不生效。
- 错误示范:
Name string = "王五" gorm:"default:'张三'"→ 插入时永远用"王五",default形同虚设 - 正确做法:去掉 Go 层初始值,靠 tag 控制;或改用指针类型(
*string),让零值真正为nil - 迁移时,
defaulttag 生成的是数据库 DDL 中的DEFAULT子句,不是 GORM 运行时逻辑
唯一约束优先用 uniqueIndex,而非 unique
gorm:"unique" 只加 UNIQUE 约束,不自动建索引;而大多数场景下你需要的是高效查找+唯一保障,这时必须配索引。GORM 推荐用 uniqueIndex,例如:gorm:"uniqueIndex:idx_phone",它既建唯一约束,也建同名索引。
-
unique在 PostgreSQL 中可能隐式建索引,但在 MySQL 里不保证——依赖引擎行为,不可靠 - 多个字段联合唯一,用
uniqueIndex:idx_user_email+ 相同 index 名,GORM 会自动合并成复合索引 - 已存在的表加
uniquetag 后运行AutoMigrate,GORM 不会删旧约束重来,得手动清理或用db.Migrator().DropConstraint
default 对 Update() 完全无效,且所有 tag 都只在 AutoMigrate 或首次建表时固化到数据库,后续改 tag 不会自动同步 schema**。


















