laravel 8 读写分离需在 mysql 连接中嵌套 read/write 并启用 sticky => true,否则所有查询走主库;read 必须为数组、write 为单元素关联数组,共用字段须置外层,sticky 开启后当前请求写后读均走主库。

直接说结论:Laravel 8 的读写分离不是“配个从库地址就自动分流”,必须把 read 和 write 嵌套在同一个连接配置里(比如 mysql),且显式启用 sticky => true,否则所有查询——包括 DB::table('users')->get() ——都走主库,从库压根没流量。
config/database.php 中 mysql 连接必须重构为 read/write 嵌套结构
常见错误是新增 mysql_slave 连接,然后在模型里写 User::on('mysql_slave')->get()。这不算读写分离,只是手动切库,不触发 Laravel 的自动路由逻辑,事务、连接复用、权重轮询全得自己兜底。
-
read必须是数组(哪怕只有一个从库也要写成[['host' => '192.168.1.10']]),不能是关联数组或字符串 -
write必须是单元素关联数组(['host' => '192.168.1.5']),不能是索引数组(如['192.168.1.5']) - 共用字段(
database、username、password、charset、driver)必须提到外层,写在read或write内部会被忽略 - 漏掉
driver => 'mysql'会导致连接初始化失败
sticky => true 是防主从延迟的刚需开关,不是可选项
默认值是 false。不开它,用户刚 save() 就 find(),大概率查不到自己刚提交的数据——这不是 bug,是 SELECT 被路由到还没同步完的从库上。
- 开启后,只要当前 HTTP 请求中执行过任何写操作(
insert()、update()、delete()、DB::statement('INSERT')),后续所有读(get()、first()、count())都强制走主库 - 该标记仅限当前请求生命周期,不影响其他请求,也不依赖 session 或 cache
- 事务内自动生效:哪怕你写的是
DB::table('logs')->select()->get(),只要在DB::transaction()里,就一定走主库 - 事务回滚后,
sticky标记仍保留——这是 Laravel 设计,业务需自行判断是否需重置
DB::table() 和 Eloquent 默认行为差异要分清
DB::table() 的读操作(get()、pluck())会触发读写分离路由;但 Eloquent 模型默认所有操作(包括 where()->get())都走 write 连接,除非你主动干预。
- 想让模型查从库,最稳妥的是在模型里加
protected $connection = 'mysql_read',前提是已在config/database.php中定义了独立的mysql_read连接(指向从库) - 临时切换可用
User::on('mysql_read')->where(...)->get(),但注意:软删除(withTrashed())、预加载(with())可能重置连接,意外切回主库 -
DB::connection('mysql')->table('users')->get()不会改变路由行为——它仍走mysql连接下的自动读写分发逻辑
最容易被忽略的点:database、username 等字段塞进了 read 数组里,或者忘了设 sticky => true。配完发现从库没请求,别急着查网络权限,先翻 config/database.php 里那几行嵌套结构和布尔值。











