CodeIgniter不支持主从同步,仅可实现读写分离;需在database.php中配置default(从库)和write(主库)两组连接,并在模型中显式调用对应数据库句柄执行读写操作。

CodeIgniter 框架本身不提供数据库主从同步功能,它也不参与 MySQL 层面的 binlog 复制或 GTID 同步。所谓“主从同步”,是数据库运维层面的事,CI 只能做读写分离(read/write split)——即让 SELECT 走从库,INSERT/UPDATE/DELETE 走主库。
你要的不是“同步”,而是“自动分发查询到不同实例”。下面直接说怎么做、为什么这么配、哪里容易翻车。
database.php 里必须定义 db['default'] 和 db['write'] 两组配置
CodeIgniter 3.x 原生支持通过数组键名区分连接,但**不会自动识别 SQL 类型并路由**——这点很多人误以为开了 db['write'] 就万事大吉,其实只是“配好了”,还没“用起来”。
-
db['default']是读库(从库),所有未显式指定的$this->db->get()、$this->db->query("SELECT ...")都走这里 -
db['write']是写库(主库),只在你手动调用时才连接,比如$this->load->database('write') - 两者必须使用完全独立的 hostname / port / user / database,不能共用同一套连接参数
-
autoinit建议设为FALSE,避免启动时无谓连接从库(尤其当从库延迟高或不可达时)
示例片段(删减版):
$db['default'] = array(
'hostname' => '192.168.1.10', // 从库 IP
'username' => 'slave_user',
'password' => 'xxx',
'database' => 'myapp',
'dbdriver' => 'mysqli',
'autoinit' => FALSE,
'pconnect' => FALSE,
);
<p>$db['write'] = array(
'hostname' => '192.168.1.5', // 主库 IP
'username' => 'master_user',
'password' => 'xxx',
'database' => 'myapp',
'dbdriver' => 'mysqli',
'autoinit' => FALSE,
'pconnect' => FALSE,
);模型里不能只靠 $this->db,得按需切换连接
CI 的 $this->db 默认绑定的是 db['default'],也就是读库。如果你在 Model 中执行了 update() 却没切库,就会报错或静默失败(取决于从库是否允许写)。
- 写操作必须显式加载写库:
$this->load->database('write', TRUE),第二个参数TRUE表示返回 DB 对象而非赋给$this->db - 更稳妥的做法是:在 Model 构造函数中初始化两个句柄,比如
$this->db_read = $this->load->database('default', TRUE);$this->db_write = $this->load->database('write', TRUE); - 所有
insert()/update()/delete()必须用$this->db_write,否则写到从库会失败(MySQL 报错ERROR 1290 (HY000): The MySQL server is running with the --read-only option)
别信“自动识别 SQL 类型”的方案,CI 3.x 原生不支持
网上很多教程教你改system/database/DB_driver.php 或重写 query() 函数,靠正则判断开头是不是 SELECT 来自动路由——这看似透明,实则埋雷:
-
INSERT INTO ... SELECT ...会被误判为读操作,发到从库,直接报错 -
SET @var := ...、CALL proc_name()等语句无法被简单前缀识别 - 多语句查询(
mysqli_multi_query)根本无法拆解 - 修改 system 文件违反 CI 升级兼容性,下次升级直接覆盖
正确做法是:业务逻辑层明确区分读写意图。比如一个订单创建流程,查用户余额用 $this->db_read,扣款和记录日志必须用 $this->db_write。
从库延迟导致读不到刚写入的数据,这是常态,不是 bug
MySQL 主从复制有天然延迟(毫秒到秒级),CI 做不了什么,但你可以控制:- 关键场景(如注册后跳转个人页)需要强一致性,就绕过从库,直接用写库查一次:
$this->db_write->get_where('users', ['id' => $id]) - 不要依赖从库的
LAST_INSERT_ID(),它在从库上不可靠,必须从写库拿 - 如果用了查询缓存(
cache_on),注意缓存键不区分读写库,可能把从库结果缓存后返回给本该走主库的请求
真正麻烦的从来不是怎么配,而是忘记“写完立刻读”这个动作在分布式数据库里本来就不安全。配置写对了,业务代码没兜住,照样出问题。


















