codeigniter 4 不内置读写分离与主从一致性保障,需手动配置多数据库组、在 model 层显式路由读写操作,并通过业务标记(如 need_master_read)处理主从延迟导致的强一致读需求。

CodeIgniter 4(CI4)本身不内置读写分离能力,必须手动实现多数据源路由逻辑,且默认不处理主从延迟带来的读一致性问题。
CI4 中配置多个数据库连接
CI4 的 app/Config/Database.php 支持定义多个数据库组,但需显式声明主库(write)和从库(read)为独立组,不能靠“自动识别”区分角色:
- 主库组名建议设为
'default'或'write',从库组名设为'read'或带编号的'read_1'、'read_2' - 每个组必须完整定义
hostname、username、password、database等字段,不能复用主库配置后仅改 host - 务必关闭从库的
DBDebug(设为false),避免因从库只读报错干扰业务逻辑 - 若使用 PDO,注意主库和从库的
DSN中字符集要一致,否则可能出现SQLSTATE[HY000] [2054] The server requested authentication method unknown to the client类错误
在 Model 层手动控制读写路由
CI4 的 Model 默认只绑定一个数据库组($DBGroup = 'default'),无法自动切库。必须重写构造逻辑或封装基类:
- 不要在
__construct()中直接调用parent::__construct(),而是先判断操作类型再选择连接:$this->db = \Config\Database::connect($isWrite ? 'write' : 'read'); - 对
insert()、update()、delete()等写操作,强制指定$this->db = \Config\Database::connect('write'); - 对
find()、findAll()、get()等读操作,默认走'read',但需预留钩子(如检查$this->forceMasterRead === true)支持强一致读 - 避免在
Builder链式调用中混用不同连接——$builder->from()->join()->where()后再换 db 实例会导致 SQL 丢失或报错Call to a member function compileSelect() on null
处理主从延迟导致的“读不到刚写的数据”
MySQL 主从复制是异步的,CI4 没有内置机制感知延迟或等待同步完成。业务层必须主动应对:
- 对关键路径(如用户注册后立即登录、订单创建后查详情),统一加标记:在 Session 或 Request 中写入
'need_master_read',后续查询前检查该标记并强制切换到'write'组 - 不要依赖
SLEEP(0.1)或重试循环来“等从库同步”,这既不可靠又增加响应时间;MySQL 本身也不提供类似SELECT ... FOR UPDATE在从库上阻塞等待的语法 - 若使用事务,确保整个事务生命周期内只用一个连接(即全走主库),否则
startTransaction()+insert()+select()可能跨库导致部分操作回滚失败 - 监控层面可定期执行
SHOW SLAVE STATUS\G查看Seconds_Behind_Master,但 CI4 应用代码里不应实时查这个值做路由决策——开销大且结果滞后
真正难的不是配两个数据库连接,而是让开发人员始终记得:哪些读可以容忍延迟,哪些必须立刻看到结果,并把这种判断固化进数据访问层的设计契约里。一旦漏掉一次强一致读的兜底,就可能在线上出现“我刚提交了,怎么查不出来”的用户投诉。











