gorm.open() 必须用 gorm.db 接收,因 gorm v1 返回指针类型,结构体字段和 getter 方法均需声明为 gorm.db;dsn 必须含 parsetime=true 以正确解析 time.time;连接池需手动设置 setmaxidleconns、setmaxopenconns 和 setconnmaxlifetime;达梦 dm8 需使用 gorm.io/driver/dm 驱动及新 dsn 格式。

gorm.Open() 返回值必须用 *gorm.DB 接收
编译报错 cannot assign *gorm.DB to dc.DB (type gorm.DB) 是最常见也最容易卡住新手的问题。根本原因不是 DSN 写错了,而是类型不匹配:GORM v1 的 gorm.Open() 永远返回 *gorm.DB,而你结构体里定义的是 gorm.DB(值类型)。
Go 不允许指针和值类型隐式转换,更关键的是:gorm.DB 内部包含连接池、回调栈、日志器等状态,按值传递会触发浅拷贝,导致后续调用 db.Create() 或事务时 panic 或静默失败。
- 结构体字段必须声明为
DB *gorm.DB - 所有 getter 方法(如
GetDB())返回类型也得是*gorm.DB - 初始化后不要重复调用
gorm.Open()—— 它本身已初始化连接池,全局复用一个实例即可
DSN 中 time.Time 处理必须显式开启 parseTime
MySQL/PostgreSQL 等数据库的 DATETIME 或 TIMESTAMP 字段在 Go 中默认映射为 string,除非你在 DSN 里加 parseTime=true。否则 time.Time 字段会变成空时间或解析失败,且无明确错误提示。
典型 DSN 示例:
user:pass@tcp(127.0.0.1:3306)/dbname?charset=utf8mb4&parseTime=true&loc=Local
-
parseTime=true是必须项,不是可选优化 -
loc=Local表示使用本地时区;若服务部署在 UTC 服务器但业务需东八区时间,应改用loc=Asia/Shanghai - SQLite 和 SQL Server 驱动不支持该参数,忽略即可;达梦 DM8 则需确认驱动版本是否兼容
连接池配置不能只靠 defer db.Close()
defer db.Close() 只关闭底层 *sql.DB,但 GORM 实例本身仍持有已失效的指针。更严重的是,它完全没触达连接池参数控制 —— 默认最大打开连接数是 0(无限),极易压垮数据库。
正确做法是在 gorm.Open() 后立刻设置:
db.DB().SetMaxIdleConns(10)<br>db.DB().SetMaxOpenConns(50)<br>db.DB().SetConnMaxLifetime(time.Hour)
-
SetMaxIdleConns控制空闲连接上限,避免连接泄漏 -
SetMaxOpenConns是硬性限制,建议设为数据库侧max_connections的 70%~80% -
SetConnMaxLifetime强制刷新老连接,防止网络闪断后连接僵死
达梦 DM8 连接要换新版驱动和 DSN 格式
老项目用 github.com/jinzhu/gorm + 自定义驱动连达梦,大概率失败。DM8 官方从 2025 年起只维护 gorm.io/driver/dm,且 DSN 不支持 tcp(...) 语法。
正确写法:
import "gorm.io/driver/dm"<br>dsn := "SYSDBA:SYSDBA@localhost:5236?database=TEST"
- 必须用
gorm.io/gorm+gorm.io/driver/dm组合,旧版jinzhu/gorm不兼容 - DSN 中去掉
tcp(),直接写host:port,参数用?分隔 - 首次连接后务必调用
db.DB().Ping(),达梦对连接验证比 MySQL 更严格











