必须填的有username:password@tcp(host:port)/dbname;易错点:tcp须小写、host禁空(推荐127.0.0.1)、parsetime=true须大写t、loc=utc须大写、charset=utf8mb4不可用utf8。

DSN 字符串里哪些参数必须填、哪些容易写错
MySQL 的 dsn 不是随便拼的,少一个关键字段或大小写/布尔值写错,gorm.Open 就会静默失败或报错如 dial tcp: lookup tcp: no such host。最常出问题的是协议部分和布尔参数。
-
username:password@tcp(host:port)/dbname这段是骨架,tcp不能写成TCP或漏掉;host不能是空字符串,本地用127.0.0.1比localhost更稳定(避免 DNS 解析干扰) -
parseTime=True必须大写True,写成true或1会导致 time 类型解析失败,查出来是零值 -
loc=Local推荐用,但注意它依赖系统时区;若需 UTC,写loc=UTC,别写loc=utc(小写不生效) -
charset=utf8mb4是当前推荐值,utf8在 MySQL 8+ 中实际只支持 3 字节,存 emoji 会截断
超时参数怎么设才真正起作用
很多人加了 timeout=5s 就以为连接 5 秒没连上就会报错,但实际不起作用——因为 GORM V2 默认不校验 DSN 里的 timeout,它只靠底层 database/sql 的连接池控制。真正生效的超时分三层:
-
timeout=5s:仅作用于单次 TCP 连接建立(即net.Dial),对已建立连接后的读写无效 -
readTimeout=30s&writeTimeout=60s:这两个才是控制 SQL 执行阶段的读写超时,必须显式加上,否则默认为 0(不限制) - 连接池层面:要用
db.DB().SetConnMaxLifetime配合SetMaxOpenConns,否则长连接可能被数据库端主动踢掉,报invalid connection
不同数据库驱动的 DSN 格式差异
达梦、PostgreSQL、SQLite 的 DSN 结构看着像 MySQL,但细节全不一样,混用会 panic。
- 达梦(
gorm.io/driver/dm):SYSDBA:SYSDBA@tcp(127.0.0.1:5236)/TEST—— 端口固定是5236,不支持charset或loc参数,加了反而报错 - PostgreSQL(
gorm.io/driver/postgres):host=localhost port=5432 user=postgres password=123456 dbname=test sslmode=disable—— 用空格分隔键值对,不是&,且sslmode=disable在本地开发必须显式声明 - SQLite(
gorm.io/driver/sqlite):test.db?_busy_timeout=5000&_journal_mode=WAL—— 没有用户密码,参数前带下划线,_journal_mode写成journal_mode会被忽略
为什么 db.AutoMigrate 有时不报错却没建表
这不是连接参数问题,但常被误认为是 DSN 配置失败。根本原因是:GORM 的 AutoMigrate 只在第一次执行时建表,且依赖当前用户对数据库有 CREATE 权限。如果权限不足,它不会 panic,只会静默跳过。
- 检查方式:用
db.Migrator().HasTable(&User{})返回false,但db.Migrator().CreateTable(&User{})报ERROR: permission denied - 生产环境应禁用
AutoMigrate,改用离线 SQL 脚本 + DBA 审核 - 测试环境可加日志:用
&gorm.Config{Logger: logger.Default.LogMode(logger.Info)},看是否输出CREATE TABLE语句
parseTime=True,它直接忽略;而达梦根本不吃任何 URL 查询参数。调试时优先看驱动文档,而不是照抄 MySQL 示例。











