每个业务模块必须使用独立的gorm.db变量,复用全局var db gorm.db是最常见错误;需为用户、订单、日志等模块分别声明userdb、orderdb、logdb,并各自调用gorm.open初始化,确保驱动、dsn、连接池及错误处理完全隔离。

每个业务模块必须用独立的 *gorm.DB 变量声明
复用同一个全局 var db *gorm.DB 是最常见错误。比如把用户、订单、日志都塞进一个 db,后续调用 db.Create() 时根本不知道连的是哪个库——尤其当 MySQL 和 PostgreSQL 混用时,驱动不匹配会静默失败或在首次查询时报 "driver: unknown driver \"postgres\"" 。
正确做法是为每个模块显式命名变量:
-
userDB *gorm.DB—— 专用于用户中心,DSN 指向 MySQL 用户库 -
orderDB *gorm.DB—— 专用于订单服务,DSN 指向分片 PostgreSQL 实例 -
logDB *gorm.DB—— 专用于写入审计日志,可能连到只读副本或 ClickHouse 兼容层
别在 func init() 里初始化:失败无法返回 error,日志无上下文;改用带返回值的初始化函数,例如 InitUserDB() (*gorm.DB, error)。
gorm.Open() 的第一个参数必须和 DSN 驱动严格对应
传 mysql.Open(dsn) 却填 PostgreSQL 的 DSN,GORM 不会在 Open() 阶段报错,而是在第一次执行 Find() 或 Create() 时卡住或返回模糊错误(如 "invalid connection" 或直接 timeout)。根本原因是方言解析失败 + 驱动未注册。
确保已导入对应驱动且带下划线:
- MySQL:
import _ "gorm.io/driver/mysql" - PostgreSQL:
import _ "gorm.io/driver/postgres"
DSN 中关键参数不能少:
- MySQL 至少含
?charset=utf8mb4&parseTime=True&loc=Local - PostgreSQL 至少含
?sslmode=disable(测试环境)或?sslmode=require(生产) - PostgreSQL 用户名/密码含
@或/时,必须用url.QueryEscape()编码,否则报"pq: password authentication failed"且无提示指向性
事务、连接池、超时都绑定在单个 *gorm.DB 实例上
userDB.Transaction() 里调用 logDB.Create(),后者完全游离在事务外——哪怕两个库物理上是同一台 PostgreSQL 实例,也无法回滚。这不是 bug,是 GORM 明确的设计边界。
连接池参数也必须单独配置,不能共用默认值:
-
userDB.Config.ConnPool = &sql.DB{}后仍需手动调用userDB.Session(&gorm.Session{}).DB.SetMaxOpenConns(20) -
logDB写入频次高但容忍延迟,可设SetMaxOpenConns(50);orderDB要求强一致性,应设更短的SetConnMaxLifetime(30 * time.Second) -
db.WithContext(ctx).Transaction()中的ctxtimeout 只约束当前实例,不影响orderDB或logDB
模型不能跨模块复用,字段映射和 SQL 方言不兼容
看似一样的 User 结构体,在 MySQL 和 PostgreSQL 上行为不同:
- MySQL 的
INT类型被 PostgreSQL 解析时可能转成int4,但 GORM 默认生成的迁移语句不会自动适配 - PostgreSQL 的双引号标识符(
"user")在 MySQL 中直接语法报错 -
DEFAULT CURRENT_TIMESTAMP在两库中含义不同:MySQL 支持列级默认,PostgreSQL 要靠函数now()
所以不要共享模型结构体直接跨库操作。应抽象接口,例如:
type UserRepository interface {
GetByID(ctx context.Context, id uint) (*User, error)
}
// 然后为 userDB 和 orderDB 分别实现
硬要统一逻辑?那就接受“查多写少”的现实:分别查再内存合并,别碰跨库事务。
最容易被忽略的一点:所有 *gorm.DB 实例都得有明确生命周期管理。没人清理的连接池会在重启时堆积 stale 连接,导致数据库侧连接数爆满。别指望 defer 或垃圾回收——它们不负责关 DB。











