gorm v2 panic 根源是传参方式错误:不再支持 gorm.open("mysql", dsn),须用驱动 open 函数(如 mysql.open(dsn))获取 sql.db 后传入;automigrate 失效多因 db 为 nil、无主键、字段忽略或类型不兼容;where 对 map/struct 不过滤零值;事务需复用同一 gorm.db 实例。

gorm.Open 为什么一调就 panic
根本原因不是 DSN 写错,而是传参方式错误:GORM v2 不再接受 gorm.Open("mysql", dsn) 这种双字符串参数写法,会直接触发 panic: unsupported driver。
必须先用对应驱动的 Open 函数获取 *sql.DB,再传给 gorm.Open:
- MySQL:导入
gorm.io/driver/mysql,调用mysql.Open(dsn) - PostgreSQL:导入
gorm.io/driver/postgres,调用postgres.Open(dsn) - SQLite:导入
gorm.io/driver/sqlite,调用sqlite.Open("test.db")
常见误写:gorm.Open("mysql", dsn) → 必须改成 gorm.Open(mysql.Open(dsn), &gorm.Config{})。漏掉驱动导入或拼错函数名(比如写成 mysql.OpenDSN)也会导致编译失败或运行时 panic。
AutoMigrate 为什么没建表或字段缺失
AutoMigrate 是单向增量操作,只增不删、不改类型、不重命名列。它不报错也不建表,往往是因为前置条件没满足。
检查这几点:
-
db实例是否为nil?忽略gorm.Open的err会导致后续所有调用静默失败 - struct 是否至少有一个字段带
gorm:"primaryKey"?否则 GORM 认为模型无效,跳过迁移 - MySQL 8+ 严格模式下,若已有同名表且某字段类型不兼容(如 Go 的
int64对应 DB 的TINYINT),整张表变更会被跳过,无提示 - 首字母小写的字段(如
name string)默认被忽略,需显式加gorm:"column:name"
验证连接是否就绪:执行 db.Migrator().CurrentDatabase(),返回空字符串说明连接未通或权限不足。
Where 传 map 或 struct 总是查不到数据
GORM 对 Where 的 map[string]interface{} 或 struct 解析不做零值过滤 —— ""、0、nil 全部当有效条件生成 SQL。
例如:Where(map[string]interface{}{"name": "", "age": 0}) 生成的是 WHERE name = '' AND age = 0,而非“忽略空值”。
安全做法:
- 手动链式拼接:
Where("name != ?", "").Where("age > ?", 0) - struct 传参更危险:字段名必须与 DB 列名**完全一致(含大小写)**,
gorm:"column:user_name"不影响Where(&User{Name: "a"})的解析逻辑 - 动态条件优先用
map[string]interface{}+ 显式判断,而不是依赖结构体自动展开
事务里 Save/Create 数据没提交
事务对象不会自动穿透到子函数。你在子函数里用的 db 如果不是从外部传入的同一实例,就根本不在事务上下文中。
典型错误:
- 在事务内重新调用
gorm.Open或使用包级全局*gorm.DB变量 - 子函数里直接用
DB.Create(...),而没把事务tx *gorm.DB作为参数传进去 - 用了
db.Session(...)但没确认该 session 是基于事务db创建的
调试技巧:打印 db.Statement.ConnPool == nil,为 false 才说明处于有效事务中。所有业务操作必须复用同一个 *gorm.DB 实例,推荐显式传参。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











