iris 本身不封装数据库连接逻辑,sql.open 或 mongo.connect 必须在 main() 启动阶段完成并显式调用 ping() 验证可用性,否则错误延迟暴露;db 初始化必须置于 app.run() 之前,严禁在路由 handler 中初始化,且所有 db 操作须传请求上下文。

直接上结论:Iris 本身不封装数据库连接逻辑,sql.Open 或 mongo.Connect 必须在 main() 启动阶段完成,且必须显式调用 DB.Ping() 或 client.Ping() 验证可用性,否则错误会延迟到第一次查询才暴露,堆栈难定位。
sql.Open + DB.Ping() 必须放在 app.Run() 之前
很多人把数据库初始化写在某个路由 handler 里,比如 app.Get("/health", func(c iris.Context) { db = sql.Open(...) }),这是错的。Iris 的 app.Run() 是阻塞调用,一旦启动就接管主线程,所有依赖数据库的预热操作(如加载配置表、初始化缓存)都会失败。
正确顺序是:
- 在
main()开头调用sql.Open("mysql", dsn)获取 *sql.DB - 立即执行
db.Ping(),捕获并处理连接/权限/网络类错误 - 调用
db.SetMaxOpenConns(20)和db.SetMaxIdleConns(5)做基础调优 - 再把
db传给 Iris 实例(如通过app.Set("db", db)或 DI 注册)
MySQL DSN 容易漏掉的三个关键参数
DSN 格式为 user:password@tcp(host:port)/dbname?params,漏掉任意一个都可能静默失败或扫描出错:
-
parseTime=true:不加会导致time.Time字段报sql: Scan error on column index 0 -
loc=Asia/Shanghai(或loc=Local):不加时时间字段可能被解析成 UTC 或零值 - 密码含
@、/等特殊字符时,必须用url.PathEscape(password)编码,否则 DSN 解析失败
示例完整 DSN:root:myp%40ss%2Fword@tcp(127.0.0.1:3306)/mydb?parseTime=true&loc=Asia%2FShanghai
主从分离得靠 GORM,Iris 不管路由逻辑
Iris 没有内置读写分离能力。如果你要用主从,得选 GORM v2 并手动配两个连接池:
- 主库 DSN 指向写节点,从库 DSN 指向读节点(host/port 必须不同)
- GORM 初始化时用
gorm.Open(mysql.Open(dsn), &gorm.Config{})分别创建*gorm.DB - 注册为全局实例:
app.Set("masterDB", masterDB)、app.Set("replicaDB", replicaDB) - 在 handler 中按语义选库:写操作用
masterDB.Create(),普通查用replicaDB.Find(),强一致读加.Session(&gorm.Session{Replicas: true})
mongo-go-driver 连接必须带 context.WithTimeout
MongoDB 客户端不能裸连,否则网络卡住会阻塞整个服务启动:
- 用
context.WithTimeout(context.Background(), 10*time.Second)包裹mongo.Connect() - 连接后立刻
client.Ping(ctx, readpref.Primary()),验证是否能连上且有权限 - 注册
*mongo.Client到 Iris 容器(推荐app.ConfigureContainer()),handler 中通过 DI 获取*mongo.Collection - 所有 DB 操作必须传请求上下文:
ctx := c.Request().Context(),绝不能用context.Background()
最常被忽略的是最后一点:用 context.Background() 做查询,会让请求取消失效、连接无法及时释放、连接池迅速耗尽。











