codeigniter 4 配置主从数据库需在 app/config/database.php 中显式定义 'default'(主库)和 'slave'(从库)两个独立连接组,驱动一致、参数分离;读操作须手动调用 \config\database::connect('slave') 获取从库实例执行,不可依赖自动路由;连接超时需通过 dsn 添加 connect_timeout 参数控制,而非 php 全局配置。

CodeIgniter 4 默认不支持主从读写分离,必须手动配置多数据源 + 自定义路由逻辑;连接超时不是靠 mysqli.default_socket_timeout 或 pdo_mysql.default_socket_timeout 解决,而是由 CI4 的 DBConnection 实例级超时参数和底层驱动行为共同决定。
CI4 怎么配主库/从库两个数据源
CI4 不像 Laravel 那样内置 read/write 连接池,得在 app/Config/Database.php 里显式定义多个组:
- 主库组(如
'default')启用'DBDebug' => true和完整错误日志,'failover' => []留空 - 从库组(如
'slave')必须单独声明,'hostname'、'username'、'password'全部独立填写,不能复用主库配置 - 两个组的
'DBDriver'必须一致(比如都是mysqli),否则Connection类实例化会失败 - 从库组建议加
'port' => 3306显式指定,避免 DNS 解析慢导致首次连接卡顿
怎么让 Model 或 Query Builder 走从库
CI4 没有 $this->db->read() 这种语法,所有读操作默认走 'default' 组。要切到从库,必须显式传入连接实例:
- 在 Model 构造函数里用
$this->db = \Config\Database::connect('slave');替换默认连接(注意:这会让整个 Model 所有操作都走从库,包括insert()—— 别这么干) - 更安全的做法是只在查询方法中临时切换:
$builder = $this->db->table('users')->get();改成$slave = \Config\Database::connect('slave'); $builder = $slave->table('users')->get(); - 不要在控制器里反复调用
\Config\Database::connect(),它每次都会新建连接;应复用连接实例或封装为服务类 - 如果用了 Query Builder 的
join(),且关联表在主库,强行走从库会查不到最新写入的数据(主从延迟导致)
连接超时到底在哪设
CI4 的数据库超时不是全局 ini 设置生效的,而是分三层控制:
-
app/Config/Database.php中每个数据源组的'DBDebug'关闭后,'port'和'hostname'错误才会触发连接超时,而不是查询超时 - 真正控制连接建立阶段超时的是底层驱动参数:
mysqli驱动需在'DSN'字符串里加?connect_timeout=5(单位秒),例如:'DSN' => 'mysqli://user:pass@192.168.1.100:3306/dbname?connect_timeout=5' -
pdo_mysql驱动则要在'DSN'后追加;connect_timeout=5,且必须确保 PHP 编译时启用了--with-pdo-mysql=mysqlnd,否则该参数被忽略 - 查询执行超时(如大表
SELECT卡住)需靠 MySQL 服务端参数wait_timeout和max_execution_time,CI4 本身不提供 query timeout 配置项
从库 read_only=1 为什么没生效
CI4 应用连上从库后仍能执行 INSERT,大概率不是代码问题,而是 MySQL 侧配置未真正生效:
- 检查运行时值:
SELECT @@read_only, @@super_read_only;,两个都必须返回1;仅配置文件写了read_only=1不够,MySQL 8.0.12+ 还要开super_read_only=ON -
root或带SUPER权限的用户不受read_only限制,CI4 连接用的账号必须没有SUPER权限 - 从库同步线程异常时(
Slave_SQL_Running: No),read_only可能自动失效,务必先跑SHOW SLAVE STATUS\G确认同步正常 - 某些云数据库(如阿里云 RDS)把
read_only设为只读参数,修改后需重启实例才生效,配置文件改了但没重启等于白改
最常被忽略的一点:CI4 的 Connection 类在构造时会执行 SET NAMES utf8mb4,如果从库 read_only=1 但没关掉 super_read_only,这条语句就会失败,导致整个连接初始化失败——此时你看到的不是“写入成功”,而是连接直接报错断开。











