beego orm v2.0.0 默认不支持读写分离,所有操作走单一主库;必须预先注册多个数据库别名(如"default"和"slave1"),再通过using()手动指定,并在prepare或工具函数中按http方法/业务上下文路由,否则将引发事务panic、关联查询走错库、values/count不继承别名及主从延迟导致写后读空等问题。

Beego ORM v2.0.0 本身不支持读写分离,所有操作默认走单一注册的数据库连接;必须手动控制 Using() 并配合上下文路由逻辑,否则写后立刻读不到、事务失效、关联查询走错库等问题会高频出现。
必须先注册多个数据库别名,否则 Using() 直接 panic
Beego 不允许在未注册的情况下调用 Using("slave1")。注册必须在 models.RegisterModel() 之后、应用启动前完成:
orm.RegisterDataBase("default", "mysql", "root:pass@tcp(127.0.0.1:3306)/master?charset=utf8mb4")orm.RegisterDataBase("slave1", "mysql", "root:pass@tcp(10.0.1.5:3306)/master?charset=utf8mb4")- 别名名(如
"slave1")需全局唯一,且不能与"default"冲突 - 若用多个从库,每个都要单独
RegisterDataBase,不能复用同一别名
事务中禁止调用 Using("slave1")
MySQL 从库不支持事务,一旦在 Begin() 后执行 <code>o2.Using("slave1").Insert(),Beego 会直接 panic 报 sql: transaction has already been committed or rolled back。
- 所有事务内操作(包括读)必须统一走
Using("default") - 若事务中需查刚写入的数据,不能切到从库——这是主从延迟之外的硬性限制
-
RelatedSel()默认不继承Using设置,必须显式链式调用:o.QueryTable("user").RelatedSel("Profile").Using("default").All(&users)
QuerySeter 的 Values() 等方法不继承 Using 设置
QueryTable("user").Using("slave1").All() 有效,但 QueryTable("user").Using("slave1").Values(&list) 仍走主库——因为 Values、ValuesList、Count 底层未透传数据库别名。
- 必须显式传参:
o.QueryTable("user").Values(&list, "Id", "Name").Using("slave1") -
Count()同理,漏掉Using()就会把读压力打到主库 -
Raw()完全绕过 ORM 路由,无论是否调用Using,都走默认连接
控制器层做轻量路由比硬切库更可控
在每个 DAO 方法里写 o.Using("slave1") 会导致业务代码高耦合、易遗漏;推荐在 Controller.Prepare() 中按 HTTP 方法预设上下文数据库标识:
- GET/HEAD 请求设
ctx.Input.Data["db"] = "slave1" - POST/PUT/DELETE 设为
"default" - 封装
GetDB(ctx *context.Context) string工具函数,避免硬编码别名 - 注意 fallback:从库不可用时,
GetDB应检测连接健康状态,降级回"default",而非让请求直接失败
主从延迟导致“写后读空”是常态,不是配置错误;关键路径(如注册后跳转个人页)必须主动走主库读,不能依赖从库一致性。











