revel框架不内置读写分离,需手动配置多数据源并自定义路由逻辑:在init()中用sql.open注册master/slave连接,dsn加read_only=1;业务层显式调用db("master")或db("slave"),事务和写后读必须走master,注意连接池管理与主从延迟处理。

Revel 框架本身不内置读写分离能力,必须靠手动配置多数据源 + 自定义路由逻辑实现。它不像 Laravel 或 Spring Boot 那样有 read/write 数组或 @ReadOnly 注解支持,所有路由决策都得你来写、来控、来兜底。
Revel 的 database.conf 怎么配主从连接
Revel 使用 conf/database.conf(或通过环境变量注入)管理数据库连接,但原生只支持单个默认连接。要支持主从,得绕过框架默认加载逻辑,自己注册多个连接:
- 在
app/init.go的init()函数里,用sql.Open()分别打开主库和从库连接,并存入全局 map 或 Revel 的AppConfig中 - 主库连接名建议设为
"master",从库设为"slave"或"slave_0",避免和 Revel 默认的"default"冲突 - 每个连接必须显式设置
SetMaxOpenConns和SetMaxIdleConns,否则高并发下容易耗尽连接 - 从库连接建议加
read_only=1到 DSN 末尾(如?read_only=1),作为防御性配置
怎么让查询自动走 slave,写操作强制走 master
Revel 没有 SQL 解析器,无法像 ProxySQL 那样自动识别 SELECT 或 INSERT。你得在业务层做显式路由:
- 封装一个
DB()工具函数,根据调用上下文返回对应连接:DB("master")或DB("slave") - 在 Service 层约定:所有以
Get、List、Count开头的方法,默认调用DB("slave");Create、Update、Delete类方法必须用DB("master") - 事务内所有 DB 操作必须统一用
DB("master"),哪怕里面混了SELECT—— 否则会跨库事务失败或读到旧快照 - 不要依赖方法名自动路由(比如 AOP 切面),Revel 的拦截器链对 DB 调用无感知,且无法覆盖所有调用路径
主从延迟时怎么避免读到脏数据
MySQL 主从延迟是常态,Revel 不提供“强一致性读”开关,你得自己补这个能力:
- 对“写后立刻读”的场景(如用户注册后跳转个人页),必须显式调用
DB("master"),不能图省事走通用查询函数 - 可以加一层轻量缓存(如本地
map[string]interface{}或 Redis),把刚写入的 ID → 结果缓存 1–2 秒,绕过从库查一次 - 如果用的是
github.com/go-sql-driver/mysql,可在从库 DSN 加timeout=3s&readTimeout=3s,防止慢从库拖垮整个请求 - 监控
Seconds_Behind_Master是必须的,但 Revel 本身不采集这个指标——得靠外部脚本定期查SHOW SLAVE STATUS并报警
最常被忽略的一点:Revel 的 DB 连接对象不是线程安全的,多个 goroutine 共享同一个 *sql.DB 没问题,但如果你在 handler 里临时 db.Exec() 后又 db.Close(),就彻底断连了。所有连接生命周期必须由初始化阶段统一管理,绝不允许运行时关闭。











