ci4的读写分离需手动指定连接组,不自动解析sql类型;$db->query()默认走主库,必须用$db->read()显式调用从库,且主从hostname、port、权限、索引、事务内连接须严格区分。

CI4 的 $db->query() 不自动识别读写分离
CodeIgniter 4 默认不解析 SQL 类型来决定走主库还是从库。即使你配置了读写分离,$db->query("SELECT * FROM users") 仍可能发到主库——除非你显式指定连接组或使用 read() 方法。
CI4 的读写分离依赖「连接组」(connection groups)而非 SQL 自动路由。它不内置 SQL 解析器,也不支持像 ProxySQL 那样的语句级分发。
- 必须手动调用
$this->db->read()获取只读连接实例,再执行查询;否则所有$db->query()都走默认连接(通常是主库) -
$this->db->write()同理,用于显式获取写连接,但写操作通常隐含在insert()/update()等方法中 - 配置文件
app/Config/Database.php中需定义至少两个连接组:'default'(主库)和'read'(从库),并设置'DBGroup' => 'read'才能生效
CI4 读写分离配置里 hostname 和 port 必须区分主从
很多人复制一份数据库配置后只改了 username 或 database,却忘了改 hostname 和 port——结果主从连到了同一台机器,压根没分流。
典型错误配置:
'default' => [
'DSN' => '',
'hostname' => '10.0.1.10',
'port' => 3306,
// ...
],
'read' => [
'DSN' => '',
'hostname' => '10.0.1.10', // ← 错!应该指向从库 IP
'port' => 3306, // ← 错!从库可能用不同端口(如 3307)
// ...
]
正确做法是确保 read 组的 hostname 指向真实从库地址,并确认该地址可被应用服务器访问、防火墙放行、MySQL 用户有对应权限。
- 从库 MySQL 账号需显式授权:例如
GRANT SELECT ON mydb.* TO 'app_ro'@'10.0.1.%' - 主库账号则需
INSERT, UPDATE, DELETE权限,且不能给从库账号写权限,避免误操作 - 若用 Docker 或 Kubernetes,注意服务发现名称是否解析正确,
localhost在容器内 ≠ 宿主机
从库索引缺失导致慢查询比主库还严重
主库建了索引,不代表从库自动生效——尤其是通过物理备份恢复的从库,或早期未同步 CREATE INDEX 语句的场景。一旦从库缺少高频 WHERE 字段的索引,SELECT 就会全表扫描,拖垮整个读链路。
常见症状:SHOW PROCESSLIST 里大量 State: Sending data,EXPLAIN 显示 type: ALL,而同样 SQL 在主库执行很快。
- 检查从库索引一致性:运行
SELECT TABLE_NAME, INDEX_NAME FROM INFORMATION_SCHEMA.STATISTICS WHERE TABLE_SCHEMA = 'mydb' ORDER BY TABLE_NAME, SEQ_IN_INDEX;对比主从 - 不要依赖「主从复制会同步 DDL」——某些 binlog 格式(如 MIXED)下 DDL 可能不记录,或中间件拦截了 DDL
- 从库
innodb_buffer_pool_size建议不低于主库的 70%,否则缓存命中率低,索引优势打折扣
transaction() 内部读操作必须强制走主库
CI4 的 $db->transStart() / $db->transComplete() 包裹的代码块,如果混入 $db->read()->query(),会导致事务跨库,MySQL 不允许,轻则报错 ERROR 1399 (XAE05): XAER_RMFAIL,重则主从数据不一致。
更隐蔽的问题是:事务中先写后读,读从库看到旧数据,业务逻辑出错(比如库存扣减后查余额仍是原值)。
- 事务内所有读写都应使用同一连接对象,即默认主库连接,不要切换到
read组 - CI4 没有类似 ShardingSphere 的
/* FORCE_MASTER */Hint 支持,只能靠代码约束:事务块里禁用$this->db->read() - 若确实需要事务后立即查最新结果,别等异步复制,直接用主库连接查,哪怕多一次查询
从库索引、连接配置、事务边界这三处,漏掉任何一个,读写分离就变成“假分流”——流量分过去了,性能没提升,反而引入延迟和不一致风险。











