835 字
4 分钟
数据源配置
GORM 数据源配置
连接流程
GORM 负责 ORM、方言和 SQL 构建;具体驱动负责连接数据库;底层连接池由 Go 标准库 database/sql 管理:
业务代码 -> *gorm.DB -> GORM Dialector/Driver -> *sql.DB -> 数据库通用初始化流程:
db, err := gorm.Open(dialector, &gorm.Config{})if err != nil { return nil, fmt.Errorf("open database: %w", err)}
sqlDB, err := db.DB()if err != nil { return nil, fmt.Errorf("get sql.DB: %w", err)}
if err := sqlDB.PingContext(ctx); err != nil { return nil, fmt.Errorf("ping database: %w", err)}gorm.Open 成功表示驱动和初始化流程成功,不应替代启动阶段的 PingContext 检查。
驱动安装
| 数据库 | 驱动包 | 连接示例 |
|---|---|---|
| MySQL / MariaDB / TiDB | gorm.io/driver/mysql | mysql.Open(dsn) |
| PostgreSQL | gorm.io/driver/postgres | postgres.Open(dsn) |
| SQLite | gorm.io/driver/sqlite | sqlite.Open("gorm.db") |
| SQL Server | gorm.io/driver/sqlserver | sqlserver.Open(dsn) |
| Oracle | 使用 GORM Oracle 驱动 | 依赖 Instant Client 和驱动文档 |
安装示例:
go get gorm.io/gormgo get gorm.io/driver/mysqlMySQL
import "gorm.io/driver/mysql"
dsn := "user:password@tcp(127.0.0.1:3306)/demo?charset=utf8mb4&parseTime=True&loc=Local"db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})DSN 常用参数:
| 参数 | 含义 |
|---|---|
user:password | 用户名和密码 |
tcp(127.0.0.1:3306) | 网络协议、地址和端口 |
/demo | 数据库名称 |
charset=utf8mb4 | 使用完整 UTF-8 字符集 |
parseTime=True | 将日期时间解析为 time.Time |
loc=Local | 时间位置 |
需要驱动高级选项时使用 mysql.New:
db, err := gorm.Open(mysql.New(mysql.Config{ DSN: dsn, DefaultStringSize: 256, DisableDatetimePrecision: true, DontSupportRenameIndex: true, DontSupportRenameColumn: true, SkipInitializeWithVersion: false,}), &gorm.Config{})PostgreSQL
import "gorm.io/driver/postgres"
dsn := "host=127.0.0.1 user=postgres password=password dbname=demo port=5432 sslmode=disable TimeZone=Asia/Shanghai"db, err := gorm.Open(postgres.Open(dsn), &gorm.Config{})如果需要关闭 pgx 的隐式 prepared statement,可使用:
db, err := gorm.Open(postgres.New(postgres.Config{ DSN: dsn, PreferSimpleProtocol: true,}), &gorm.Config{})SQLite
import "gorm.io/driver/sqlite"
db, err := gorm.Open(sqlite.Open("gorm.db"), &gorm.Config{})内存数据库适合测试:
db, err := gorm.Open(sqlite.Open("file::memory:?cache=shared"), &gorm.Config{})SQLite 驱动可能涉及 CGO;若项目要求纯 Go 实现,应按所选替代驱动的文档配置,而不是直接假设所有 SQLite 驱动行为相同。
SQL Server
import "gorm.io/driver/sqlserver"
dsn := "sqlserver://user:password@127.0.0.1:1433?database=demo"db, err := gorm.Open(sqlserver.Open(dsn), &gorm.Config{})连接字符串包含特殊字符时,需要按驱动规则进行 URL 编码,尤其是密码中的 @、:、/ 和 ?。
从环境变量读取配置
不要把真实密码提交到笔记或源码:
type DatabaseConfig struct { DSN string MaxIdleConns int MaxOpenConns int ConnMaxLifetime time.Duration}
func OpenMySQL(cfg DatabaseConfig) (*gorm.DB, error) { db, err := gorm.Open(mysql.Open(cfg.DSN), &gorm.Config{}) if err != nil { return nil, err }
sqlDB, err := db.DB() if err != nil { return nil, err } sqlDB.SetMaxIdleConns(cfg.MaxIdleConns) sqlDB.SetMaxOpenConns(cfg.MaxOpenConns) sqlDB.SetConnMaxLifetime(cfg.ConnMaxLifetime) return db, nil}DB_DSN='user:password@tcp(127.0.0.1:3306)/demo?charset=utf8mb4&parseTime=True&loc=Local'生命周期与连接池
sqlDB, err := db.DB()if err != nil { return err}
sqlDB.SetMaxIdleConns(10) // 空闲连接上限sqlDB.SetMaxOpenConns(100) // 打开连接上限sqlDB.SetConnMaxLifetime(time.Hour) // 连接最大复用时长sqlDB.SetConnMaxIdleTime(10 * time.Minute)
defer sqlDB.Close() // 应用退出时关闭;不要每次请求都 Close连接池参数没有通用最佳值,应结合数据库 max_connections、应用实例数量、请求并发和慢查询情况压测。MaxOpenConns 是单个应用实例的上限,不是整个集群的上限。
复用已有 *sql.DB
已经由其他组件创建连接时,可以把它交给 GORM:
sqlDB, err := sql.Open("mysql", dsn)if err != nil { return err}
db, err := gorm.Open(mysql.New(mysql.Config{Conn: sqlDB}), &gorm.Config{})此时连接池仍由这个 sqlDB 管理,避免同一数据库无意中创建两套连接池。
常见问题
parseTime=True缺失:MySQL 的时间字段可能无法直接映射到time.Time。- 字符集使用
utf8:MySQL 的utf8不是完整四字节 UTF-8,优先使用utf8mb4。 - 只调用
gorm.Open不 Ping:启动时无法及时发现网络、认证或数据库不可用。 - 每次请求创建连接:会造成连接池失控,应在应用启动时创建一次
*gorm.DB。 - 把 DSN 拼接用户输入:可能产生连接配置注入或解析错误,DSN 应来自可信配置。
官方资料
分享文章
生成精美分享图或复制链接,与更多人分享本文。
继续阅读
换条路线
从其他文章中稳定抽取
最后更新于 ,距今已过 77 天
部分内容可能已过时