codeigniter 4 不内置读写分离,需手动配置主从数据库连接并在模型中显式调用;$writedb 用于写操作,$readdb 用于读操作,强一致性场景必须走主库,权限错误仅在查询时暴露。

CodeIgniter 4 不内置读写分离机制,必须手动配置多个数据库连接 + 在模型或服务层做语句分发。所谓“自动识别 SELECT/INSERT 并路由”是旧版 CI 的民间扩展玩法,CI4 官方不支持,硬套会踩坑。
database.php 里定义主从两组连接
打开 app/Config/Database.php,在 $default 配置下方新增 $writedb 和 $readdb(命名任意,但建议语义化):
-
$writedb必须指向主库,hostname、username、password、database填真实值;DBDriver要和主库一致(如MySQLi); -
$readdb指向从库,注意从库账号需有SELECT权限,且不能有INSERT/UPDATE/DELETE权限——这是防误写的最后一道防线; - 两个连接的
DBPrefix建议保持一致,否则跨库 JOIN 会出错; - 别设
autoConnect => true,CI4 默认已连接,默认连接的是$default,多连反而浪费连接数。
模型中按需加载并明确指定连接对象
CI4 的 $this->db 是单例,不能临时切换。想用从库,就得显式加载:
- 在 Model 构造函数里用
$this->writedb = \Config\Database::connect('writedb');加载主库; - 同理用
$this->readdb = \Config\Database::connect('readdb');加载从库; - 写操作必须用
$this->writedb->table(...)->insert(); - 读操作推荐用
$this->readdb->table(...)->get(); - 不要试图把
$this->readdb赋给$this->db,这会导致后续所有未指定对象的查询都走从库,包括你忘了改的写逻辑。
避免“伪读写分离”:SELECT 语句也可能要走主库
刚写入的数据立即被查(比如注册后跳转到个人页),从库可能因复制延迟返回旧数据。这时必须强制走主库:
- 不要依赖“所有 SELECT 都走从库”的假设;
- 对强一致性场景(如订单创建后立刻查状态),直接用
$this->writedb->table(...)->get(); - 可封装一个辅助方法,例如
getWithConsistency(),内部固定调用$this->writedb; - 如果项目里大量存在这类需求,说明当前主从架构或业务逻辑设计有问题,不是框架配置能解决的。
验证连接是否生效的最简方式
别靠日志猜,直接在控制器里写两行调试代码:
$w = \Config\Database::connect('writedb');
$r = \Config\Database::connect('readdb');
var_dump($w->getPlatform(), $r->getPlatform()); // 应分别输出 'MySQLi' 和 'MySQLi'
echo $w->table('users')->countAll(); // 主库用户总数
echo $r->table('users')->countAll(); // 从库用户总数(应一致,否则复制异常)
真正容易被忽略的点是:CI4 的数据库连接默认不校验权限,即使从库账号没给 SELECT 权限,connect() 也会成功,直到执行第一条查询才报错——错误信息是 SQLSTATE[HY000]: General error: 1142 SELECT command denied,不是连接失败。











