必须显式指定loc=local或loc=asia%2fshanghai,否则time.time字段按utc解析导致8小时偏移;parsetime=true必须开启,否则time.time被当字符串处理;charset=utf8mb4需强制指定,特殊字符密码要url编码。

gorm.Open 连接数据库时 dsn 字符串必须显式指定时区
不加 loc=Local 或 loc=Asia%2FShanghai,time.Time 字段在读写时会按 UTC 解析,导致时间偏移 8 小时。这不是 GORM 的 bug,而是 MySQL 驱动默认行为。
常见错误现象:Birthday 字段存入 2025-01-01,查出来变成 2024-12-31;或 CreatedAt 显示为凌晨 3 点。
-
parseTime=True必须开启,否则time.Time会被当作字符串处理 -
charset=utf8mb4推荐强制指定,避免 emoji 或四字节 UTF-8 存储失败 - 密码含特殊字符(如
@、/)需 URL 编码,例如user:pass%40word@tcp(...)
db.AutoMigrate 执行后表结构没更新?检查 struct tag 和主键定义
AutoMigrate 不是“智能同步”,它只做「新增字段/索引/约束」,不会删除字段、修改类型或重命名列。很多开发者以为改了 struct 就能自动生效,结果发现旧字段还在、新字段没加进去。
关键点:
- 字段名必须导出(首字母大写),且 struct 必须有主键 ——
gorm.Model自带ID uint,但自定义主键要显式标gorm:"primaryKey" -
gorm:"size:200"只影响VARCHAR长度,对TEXT或INT无效;想建TEXT字段得用gorm:"type:text" - 如果已存在表且字段类型不兼容(比如把
int改成*time.Time),AutoMigrate会静默跳过,不报错也不执行
SetMaxOpenConns / SetMaxIdleConns 必须在 gorm.DB 获取 sql.DB 后调用
很多人在 gorm.Open 后直接对 *gorm.DB 调用连接池设置,结果完全无效 —— 因为 GORM 的连接池控制实际在底层 *sql.DB 上。
正确顺序:
- 先调
db.DB()获取*sql.DB实例 - 再调
SetMaxOpenConns(100)、SetMaxIdleConns(20)、SetConnMaxLifetime(time.Hour) - 注意
SetConnMaxLifetime单位是time.Duration,别传60 * time.Minute这种冗余写法,直接用time.Hour更清晰
漏掉这一步,高并发下容易出现 dial tcp: lookup xxx: no such host 或连接耗尽超时。
Beego ORM 的 orm.RegisterModel 必须传指针类型,且不能重复注册
Beego ORM 要求模型注册必须用 new(User) 或 &User{},传值类型(如 User{})会导致运行时报 reflect: call of reflect.Value.Type on zero Value。
另一个易踩坑点:同一个 model 在多个 init 函数里重复 RegisterModel,Beego 会 panic 报 model already registered,但错误堆栈不指向你自己的代码,排查困难。
建议做法:
- 所有模型注册统一放在一个
models/init.go文件的init()函数中 - 用
orm.RegisterModel(new(User), new(Post), new(Comment))一行注册多个,避免遗漏或重复 - 若用
go run启动,确保models包被 import,否则init()不执行
真正麻烦的不是配置本身,而是错误发生时 GORM 或 Beego 往往不报具体哪行 struct tag 写错了、哪个字段没导出、哪次 AutoMigrate 其实被跳过了 —— 它们倾向于沉默,把问题留给日志和调试器。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











