CI4实现读写分离需自定义ConnectionInterface类并绑定服务容器,禁用默认Database::connect(),读操作走ReadConnection、写操作走WriteConnection,Model中重写find等方法显式调用对应连接,强一致性场景通过context标记强制主库,事务内所有查询必须走主库。

CI4 里怎么配读写分离?别碰 database.php 的默认配置
CodeIgniter 4 默认不支持开箱即用的读写分离,直接在 database.php 里写两个 DSN 或堆多个 default 配置项是无效的——框架会忽略第二个,或报 DatabaseException: No database connection settings were found。
真正可行的方式是:自定义 ConnectionInterface 实现类,配合服务容器绑定,并在 BaseModel 或 DAO 层做路由判断。关键点在于绕过 CI4 原生的 DB() 工厂函数直连逻辑。
- 必须禁用
$db = \Config\Database::connect()这类全局连接调用,否则永远只走主库 - 所有读操作应通过自定义的
ReadConnection类获取实例,写操作走WriteConnection - CI4 的
BaseModel不会自动识别读/写上下文,需重写find()、findAll()等方法,内部显式调用对应连接 - 不要试图用
.env多配几个database.default.前缀——CI4 的Database配置类只认一个default键
主从延迟下,哪些查询必须走主库?别信“所有 SELECT 都能读从库”
CI4 没有内置的“强一致性读”标记机制,所以你得自己加判断逻辑。常见踩坑是:用户刚注册完立刻查 UserModel->findByEmail(),结果返回 null——因为从库还没同步完。
这类场景必须强制走主库,且不能靠时间戳或 sleep 补救(延迟不可控)。建议用轻量级路由标记:
- 在 Service 层调用前,用
session()->set('force_master', true)或context()->set('read_from_master', true)(需自行实现 context) - 自定义连接类中检查该标记,命中则跳过从库选择逻辑,直连主库
- 对事务内所有查询(哪怕只是
SELECT ... FOR UPDATE)也必须走主库,否则会触发Deadlock found when trying to get lock - 避免在 Model 构造函数里做连接选择——构造时无法预知后续是读是写;应在每个具体方法入口判断
CI4 能不能做数据分片?别硬改 BaseModel 的 $table
CI4 原生完全不支持分库分表,强行在 $table 属性里拼接后缀(如 'user_'.date('Ym'))会导致迁移、种子、验证器全部失效,且 forge 无法识别动态表名。
真要分片,只有一条路:把分片逻辑下沉到 DAO 层,且必须放弃 BaseModel 的自动 CRUD 封装。
- 分片键(如
user_id)必须在 Service 层就确定,传入 DAO 后由 DAO 计算目标库+表,再手动 new 对应的Connection和Query - 跨分片
JOIN或UNION查询必须由应用层收口合并,CI4 的 Query Builder 不支持多源表自动路由 - 不要覆盖
BaseModel::insert()方法去自动分表——它不参与事务管理,也无法保证主键生成与分片一致 - 分片后的迁移脚本需独立维护,不能依赖
php spark migrate全局执行;每个分片库要单独跑对应版本
代理层 or 组件层?CI4 项目里该选哪条线?
在 CI4 中引入 MyCat 或 MaxScale 这类代理层,看似省事,实则掩盖了延迟和失败场景——比如从库宕机时,代理可能静默切到其他从库,但 CI4 应用层完全感知不到,日志里只有超时或空结果。
更可控的做法是用组件层 + 显式连接管理:
- 用
mysqli或PDO手动管理多个连接实例,封装成MasterConnectionPool和SlaveConnectionPool - 健康检查必须由应用层主动做(例如每 30 秒发
SELECT 1),不能依赖代理的心跳 - CI4 的
Events系统可监听db:query,记录慢查询来源(主/从)、错误类型(SQLSTATE[HY000] [2002]还是SQLSTATE[08S01]),这是排查分片或延迟问题的关键线索 - 最易被忽略的是:所有
cache驱动(如 file、redis)必须带库标识前缀,否则主从切换后缓存 key 冲突会导致脏读

















