gorm v2 初始化必须用 mysql.open(dsn),不能传字符串驱动名;需导入 gorm.io/driver/mysql 并下划线导入,dsn 必含 parsetime=true&loc=local,连接池须手动配置 db.db().setmaxopenconns 等参数。

GORM 初始化必须用 mysql.Open(),不能传字符串
很多人照着旧教程写 gorm.Open("mysql", "user:pass@tcp(...)"),直接 panic:`unsupported driver "mysql"`。GORM v2 已彻底移除字符串驱动名机制,必须显式导入并使用对应数据库的 Dialector 实例。
- MySQL 必须先
go get gorm.io/driver/mysql,然后调用mysql.Open(dsn) - PostgreSQL 对应
postgres.Open(dsn),SQLite 是sqlite.Open(file) -
dsn字符串格式与 v1 一致,但解析逻辑已下沉到各驱动内部,比如 MySQL 仍支持user:pass@tcp(127.0.0.1:3306)/dbname?charset=utf8mb4&parseTime=True - 别漏掉
&gorm.Config{}第二个参数,否则默认不启用日志、不自动迁移、不处理软删除字段
连接池配置不能只靠 gorm.Config
gorm.Config 只控制 ORM 层行为(如日志、命名策略),真正的连接池由底层 *sql.DB 控制。如果没手动设置,Go 默认最大连接数是 0(无限制),高并发下容易打爆数据库。
- 初始化 GORM 后立刻调用
db.DB().SetMaxOpenConns(n)和db.DB().SetMaxIdleConns(m) - 生产环境建议
MaxOpenConns = 50~100,MaxIdleConns = 20~50,具体看 DB 规格和 QPS - 别忘了
db.DB().SetConnMaxLifetime(1h)和SetConnMaxIdleTime(30m),避免 DNS 变更或连接空闲超时导致 stale connection
在 Fiber 中安全传递 *gorm.DB 实例
Fiber 的 Ctx 不适合存 DB 实例(生命周期不匹配、易引发 goroutine 泄漏)。正确做法是在启动时初始化一次,通过依赖注入或全局变量暴露,再在 handler 中直接使用。
- 推荐放在
internal/pkg/database/db.go里定义一个包级变量var DB *gorm.DB,并在cmd/main.go启动时初始化 - 不要在每个 handler 里重复调用
gorm.Open()—— 这会新建连接池,浪费资源且无法复用连接 - 若需多数据源(如读写分离),分别初始化
WriteDB和ReadDB,用不同变量名隔离,避免混用 - 务必在
main()退出前调用DB.Close(),否则进程可能 hang 住
软删除字段要显式启用,否则 DeletedAt 不生效
GORM 默认把 DeletedAt 当普通字段,不会自动加 WHERE deleted_at IS NULL。即使你嵌入了 gorm.Model,也得确认配置是否开启软删除。
- 初始化时传入
&gorm.Config{NowFunc: func() time.Time { return time.Now().UTC() }}(可选,统一时间时区) - 确保模型字段类型是
gorm.DeletedAt,不是*time.Time或time.Time - 如果想全局禁用软删除(比如做数据归档),查询时用
Unscoped();但日常 CRUD 必须依赖它,否则Delete()只是更新deleted_at,不是真删
最常被忽略的是连接池参数和 Unscoped() 的误用——前者导致数据库被打满,后者让软删除形同虚设,查出来的数据永远“多一条”。











