CI4读写分离需手动统一主从库字符集,否则易乱码;必须在write和每个read连接中分别配置charset和collation,验证五项MySQL字符集变量及表字段collation一致性。

CI4 读写分离配置本身不自动解决字符集问题,必须手动确保主从库字符集完全一致,否则一写多读场景下极易出现乱码或插入失败。
读写分离配置中 character_set_client 不同步的典型表现
CI4 使用 $db['default']['read'][] 和 $db['default']['write'] 分离连接后,若主库和从库的 character_set_client、character_set_connection、character_set_results 不一致,会出现:插入中文成功但从从库查出来是问号、emoji 存成 、SET NAMES utf8mb4 在写连接生效却未在读连接执行。
- CI4 默认只对
write连接执行init配置(如charset),read数组里的每个从库连接需单独配charset -
charset参数仅影响连接初始化时的character_set_client和character_set_connection,不控制character_set_results,后者依赖SET NAMES或连接参数 - MySQL 8.0+ 默认
collation_server是utf8mb4_0900_ai_ci,而 CI4 的charset参数设为utf8mb4时,不会自动匹配该 collation,需显式指定collation
database.php 中 read/write 连接必须分别指定 charset 和 collation
不能只在 write 里设 charset,然后指望 read 继承。CI4 对每个 read 实例都新建独立连接,必须逐个配置。
- 在
database.php的$db['default']['write']和每个$db['default']['read'][n]下,都加上:'charset' => 'utf8mb4'、'collation' => 'utf8mb4_unicode_ci' - 如果使用 MySQLi 驱动,还需额外加
'DSN' => 'charset=utf8mb4'(PDO 驱动则通过charSet和attributes控制) - 避免用
init执行SET NAMES utf8mb4—— CI4 的init只作用于 write 连接,且不同读库可能有不同执行时机,不可靠
验证主从库字符集是否真正统一
光看 CI4 配置没用,必须登录到每个 MySQL 实例(主 + 所有从)运行检查命令,确认五处关键变量全为 utf8mb4:
character_set_clientcharacter_set_connectioncharacter_set_databasecharacter_set_resultscharacter_set_server
执行 SHOW VARIABLES LIKE 'character_set_%';,任一节点只要有一项不是 utf8mb4,就存在风险。特别注意:从库的 character_set_server 默认继承自配置文件,但若主库 binlog 写入时用了非 utf8mb4 字符集,即使从库配置正确,回放后字段实际存储仍可能是乱码。
已有数据表迁移时容易忽略的 collation 一致性
修改 CI4 连接配置只是第一步,表结构本身的 COLLATE 必须与连接层匹配,否则 WHERE name = '张三' 在读连接里可能因排序规则差异导致索引失效或结果错乱。
- 执行
SHOW CREATE TABLE users;,确认每列(尤其是VARCHAR)的COLLATE是utf8mb4_unicode_ci,而非utf8mb4_general_ci或latin1_swedish_ci - 批量转换用:
ALTER TABLE users CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; - 只改表默认 collation 不等于改字段 collation,
CONVERT TO是安全做法;MODIFY COLUMN单独改字段时必须显式带COLLATE utf8mb4_unicode_ci
主从延迟、连接复用、字段级 collation 遗留问题,才是读写分离下字符集出错的真正高发点。配置写完别急着上线,先连上每个从库手动跑一遍 SELECT HEX('中文') 看返回值是否一致。

















