Iris本身不提供数据库主从分离内置支持,需依赖GORM v2等ORM手动配置主库(Write)与从库(Read)连接池,按方法语义路由:Create/Update/Delete走主库,Find/First默认走从库,事务内全走主库,强一致读须显式标注Write或Session。

Iris 本身不提供数据库主从分离的内置支持,它只是 Web 框架,不介入 ORM 或数据库连接池管理。主从路由、读写分离逻辑必须由你选用的数据库驱动或 ORM 层实现,Iris 只负责把配置传进去、把连接实例初始化好。
用 GORM v2 配置主从分离(最常用场景)
绝大多数 Iris 项目搭配 GORM 使用。GORM v2 原生支持 ReplicaDB 机制,需手动配置多个 *gorm.DB 实例并注册为“主库”和“从库”:
- 主库(
Write)用于Create/Update/Delete和事务 - 从库(
Read)用于Find/First等查询,默认走从库;加Session(&gorm.Session{Replicas: true})强制走主库 - 连接字符串里不能共用同一地址:主库和从库的
host、port必须不同,否则无法区分 - 注意 GORM 的
Open返回的是*gorm.DB,不是*sql.DB;Iris 中只需把它挂到app.Logger()或自定义容器(如app.Set("db", db))里供 handler 使用
示例关键片段:
masterDSN := "user:pass@tcp(10.0.1.10:3306)/mydb?charset=utf8mb4&parseTime=True"
slaveDSN := "user:pass@tcp(10.0.1.11:3306)/mydb?charset=utf8mb4&parseTime=True"
master, _ := gorm.Open(mysql.Open(masterDSN), &gorm.Config{})
slave, _ := gorm.Open(mysql.Open(slaveDSN), &gorm.Config{})
db, _ := gorm.Open(mysql.New(mysql.Config{
ConnPool: master,
Replicas: []gorm.Dialector{mysql.Open(slaveDSN)},
}), &gorm.Config{})
用 sqlx 或 database/sql 手动分发查询(轻量级选择)
如果你没用 ORM,而是直接用 database/sql + sqlx,就得自己写路由逻辑:
- 初始化两个
*sql.DB:一个连主库(writeDB),一个连从库(readDB) - 在 handler 中显式决定用哪个:写操作用
writeDB.Exec(...),读操作用readDB.QueryRow(...) - 别在中间件里自动切换——容易误判(比如 POST 请求里带了
SELECT子查询) - 注意
readDB的SetMaxOpenConns通常要设得比writeDB更高,因为读请求并发更高
常见错误现象:sql: transaction has already been committed or rolled back —— 因为在事务中混用了 readDB 和 writeDB,事务只对创建它的那个 *sql.DB 有效。
配置项命名和加载位置容易被忽略
Iris 不管你怎么配数据库,但你得确保配置能被正确加载进业务层:
- 别把数据库配置硬编码在
main.go里;推荐用iris.Configuration的WithConfiguration加载 YAML/JSON,再通过app.ConfigureHost注入全局变量或结构体 - YAML 示例中,主从字段名建议统一用
master/replicas(而非primary/secondary),避免和某些 ORM 的关键字冲突 - 环境变量覆盖时,
DB_MASTER_URL和DB_REPLICA_URL要分别设置,不能只设一个DB_URL然后靠代码拼接 - 如果用
go-config或viper,注意它们默认不支持多层级嵌套的 replica 列表解析,需手动展开
主从延迟导致的脏读问题,Iris 无能为力;该加 FOR UPDATE 的地方不能省,该强制走主库的查询不能依赖“运气”。配置只是第一步,读写分离的语义正确性,始终由你控制。


















