Laravel的DB::connection()默认走'default'连接,读写分离需配置read/write分组或显式指定连接名;事务中所有查询强制走主库;Eloquent默认全走主库,需用on()或$connection指定从库;主从延迟需业务层兜底。

MySQL 主从配置后 DB::connection() 为什么还是连主库?
默认情况下,Laravel 的 DB::connection()(不传参数)永远走 'default' 连接,而读写分离不是靠“自动切换”,是靠显式指定连接名或使用查询构造器的读操作触发路由逻辑。
真正起作用的是 Laravel 内置的 read / write 连接分组机制,它只在你用 DB::table()->get()、DB::select() 等读方法时,才尝试从 read 组挑一个连接;写操作(如 insert()、update())才走 write 组——但前提是你的配置里有明确的 read 和 write 子键。
- 检查
config/database.php中mysql配置是否包含'read'和'write'键,而不是只有'host' -
'read'必须是数组,哪怕只配一个从库:'read' => ['host' => '192.168.1.10'] - 不要手动调
DB::connection('slave')——Laravel 不认这个连接名,除非你单独定义了一个叫slave的独立连接 - 如果你用了
DB::connection('mysql'),它仍走默认逻辑,不会自动拆读写
如何让 Eloquent 模型强制走从库?
Eloquent 默认所有操作都走 write 连接(即主库),因为模型没区分读写意图。想让它查数据时走从库,得主动干预路由决策。
- 最稳妥的方式:在模型里加
protected $connection = 'mysql_read';,并提前在config/database.php中定义一个独立的mysql_read连接(指向从库) - 更灵活的做法:用
on('mysql_read')临时切换:User::on('mysql_read')->where('active', 1)->get() - 避免用
DB::table('users')+on()混用 Eloquent 模型——连接切换不会继承模型的$casts或accessors - 注意:软删除(
withTrashed())和关联预加载(with())会重置连接,可能意外切回主库
DB::transaction() 里执行 select() 为什么会连主库?
事务期间,Laravel 强制所有查询(包括 select)都走同一个连接,且该连接必须是可写的——也就是主库。这是为保证事务一致性,无法绕过。
- 只要进了
DB::transaction(),哪怕你写DB::table()->select()->get(),也一定走write连接 - 试图在事务里用
on('mysql_read')会抛错:Cannot execute queries while other uncommitted transactions are active - 如果只是想“先查再写”,且查的数据不参与事务隔离,就别包进事务——把
select提到事务外 - 读多写少场景下,别为了省一次查询硬塞进事务,反而拖慢从库分流效果
从库延迟导致 insert() 后立刻 get() 查不到?
这是主从同步延迟的典型表现,Laravel 不解决这个问题,它只负责把读请求发给从库——至于数据有没有同步过来,得你自己兜底。
- 对强一致性要求高的操作(比如注册后立刻显示用户信息),直接用
DB::connection('mysql_write')查主库 - 不要依赖从库做“写后即读”(read-after-write),尤其在高并发或跨机房部署时延迟可能达数百毫秒
- 可以用
DB::afterCommit()做异步补偿,但不能解决实时性问题 - 监控
Seconds_Behind_Master,延迟超过阈值时临时降级读主库(需自定义连接工厂逻辑)
读写分离不是开个配置就完事,真正的难点在边界:事务、一致性、延迟感知、连接复用。这些地方一不留神,流量全打到主库上,还查不出原因。



















