GORM连接达梦数据库必须使用第三方Dialector驱动(如godoes/gorm-dm),不能直接用官方mysql或postgres驱动;需显式导入并调用dm.Open(dsn),DSN格式为username:password@tcp(127.0.0.1:5236)/database,密码含特殊字符须用url.PathEscape编码,且仅支持DM8。

GORM 不能直接用官方 gorm.io/driver/mysql 或 postgres 连到达梦,必须使用第三方适配的 Dialector 驱动,否则会报错 driver: unknown driver "dm" (forgotten import?)。
必须用 github.com/godoes/gorm-dm 驱动
达梦没有被 GORM 官方收录,社区主流方案是 godoes/gorm-dm(适配 DM8)。它实现了 GORM 的 Dialector 接口,封装了连接逻辑和 SQL 方言转换(比如分页用 limit ? offset ? 而非 rownum)。
常见错误现象:
- 直接写
gorm.Open("dm", dsn)→ panic:driver: unknown driver "dm" - 忘记
import驱动包 → 编译通过但运行时报 driver not found
正确做法:
import (
"gorm.io/gorm"
dm "github.com/godoes/gorm-dm" // 必须显式导入
)
dsn := "SYSDBA:SYSDBA@tcp(127.0.0.1:5236)/TEST"
db, err := gorm.Open(dm.Open(dsn), &gorm.Config{})
注意:godoes/gorm-dm 目前只支持 DM8,不兼容 DM7;若用 DM7,需降级到旧版驱动或改用 ODBC + alexbrainman/odbc。
dsn 格式必须严格匹配达梦协议
GORM 的 dm.Open() 接收的 DSN 是自定义格式,不是 JDBC URL,也不能套用 MySQL 风格。标准格式为:
username:password@tcp(host:port)/database?param=value
关键点:
-
host不能写localhost(部分版本解析失败),建议用127.0.0.1 -
port默认是5236,必须显式写出,不能省略 -
database是数据库名(即达梦实例名),不是 schema 名;schema 在建表时通过schema.Table指定 - 不支持
charset=utf8等 JDBC 参数;字符集由达梦服务端决定,客户端乱码需在 OS 层设置LANG=zh_CN.UTF-8
错误示例:
// ❌ 错误:用了 JDBC 格式 "jdbc:dm://127.0.0.1:5236/TEST?charset=utf-8" // ❌ 错误:省略 port 或用 localhost "SYSDBA:SYSDBA@tcp(localhost)/TEST"
密码含特殊字符时要 URL 编码
如果达梦密码里有 @、/、:、? 等字符,username:password@... 会解析失败,导致连接报错 parse dsn failed 或 invalid port。
解决方式是手动对 password 做 URL 编码:
import "net/url" pwd := "P@ss/w0rd?123" encodedPwd := url.PathEscape(pwd) dsn := encodedPwd + "@tcp(127.0.0.1:5236)/TEST" // 实际拼成:P%40ss%2Fw0rd%3F123@tcp(127.0.0.1:5236)/TEST
注意:url.QueryEscape 不适用(它会把 / 编成 %2F,但 DSN 解析器要求路径分隔符保持原样),必须用 url.PathEscape。
事务自动提交行为与 autoCommit 设置
达梦默认开启 auto-commit,但 GORM 初始化后会设为 autoCommit = false(符合 ORM 习惯)。这意味着:
- 单条
Create/Save不会立即落库,需显式db.Commit()或用Transaction函数包裹 - 若没 commit 就 close 连接,数据会回滚,看起来“插入成功但查不到”
验证方法:
tx := db.Begin()
tx.Create(&User{Name: "test"})
fmt.Println(tx.Error) // nil,但数据库里还查不到
tx.Commit() // 此时才真正写入
容易忽略的是:GORM 的 db.Session(&Session{PrepareStmt: true}) 不影响 autoCommit 行为,该设置只控制预编译开关。


















