Laravel读写分离需在database.php中为连接配置'read'和'write'子键,否则所有查询默认走主库;读操作自动路由至从库(按host顺序尝试),写操作强制走主库,无自动故障转移;DB::failover()非原生功能。

连接池里没配好 read/write 分离,切库根本不会触发
Laravel 的 DB 门面默认走的是 write 连接(即主库),哪怕你配置了多个数据库连接,select 查询也不会自动落到从库——除非你显式调用 DB::connection('read')->select(...),或者启用了读写分离机制。
真正让 Laravel 自动分流的关键,是把多个连接按角色归类进 connections 配置,并在 database.php 中声明 'read' 和 'write' 子键:
'mysql' => [
'read' => [
'host' => ['192.168.1.10', '192.168.1.11'],
],
'write' => [
'host' => '192.168.1.5',
],
'driver' => 'mysql',
// ... 其他通用配置
],
- 必须把从库地址塞进
'read' => ['host' => [...]],不能只写一个'host'字符串 -
'write'只能是一个连接,不支持数组;主库挂了就真断了,Laravel 不会自动切另一个“主库” - 如果没配
'read',所有查询(包括DB::table(...)->get())都走'write',故障转移无从谈起
主库宕机后,查询直接报错而不是降级到从库
Laravel 默认不做“连接失败时自动 fallback 到从库”的事。它只会在执行 select 时尝试连 read 连接池里的第一个可用 host;但如果你的代码写了 DB::table(...)->update(...) 或 DB::transaction(...),它铁定打向 write 连接——此时主库挂了,就是 PDOException: SQLSTATE[HY000] [2002] Connection refused,没商量。
- 读操作(
select,count,exists等)才会走read连接池,且按顺序试连,遇到第一个通的就用 - 写操作、事务、
DB::statement()、DB::unprepared()全部强制走write,无法绕过 - 想让部分“只读语义”的写法也走从库?不行。比如
DB::table('users')->where('id', 1)->value('name')是 select,可走从库;但DB::table('users')->where('id', 1)->update(['name' => 'x'])必走主库
DB::failover() 不是 Laravel 原生功能,别被文档外的包带偏
网上有些文章提到 DB::failover() 或类似方法,那是第三方包(如 laravel-db-failover)加的扩展,Laravel 核心从没提供这个 API。原生 DB 类里搜不到 failover 方法,强行调用会抛 BadMethodCallException。
Laravel Cloud(cloud.laravel.com)。此技能用于处理所有 Laravel Cloud 请求,包括搜索和读取数据。只要任务涉及 Laravel Cloud,即使用此技能。
- 官方只支持“读写分离”,不支持“主库故障时自动把读+写都切到备用节点”这种跨角色切换
- 真要实现写操作的故障转移,得自己封装:比如监听
Illuminate\Database\Events\StatementPrepared,捕获连接异常后重试到预设的灾备主库(需手动维护连接配置) - 更现实的做法是:主库挂了就告警+人工介入,或用数据库层高可用(如 MHA、Orchestrator、ProxySQL)接管 VIP/路由,对 Laravel 透明
从库延迟导致数据不一致,比连不上还难排查
连接切过去了,查询也成功了,但用户刚提交的订单查不到——这不是故障转移失效,而是从库同步延迟。Laravel 不感知复制 lag,DB::connection('read') 拿到的就是当前从库的实时快照,哪怕它落后主库 3 秒。
- 对强一致性要求高的场景(如支付回调查订单状态),必须强制走主库:
DB::connection('mysql')->table(...)->get() - 可以给关键读加
DB::connection('mysql')->disableQueryLog()防止日志干扰,但解决不了延迟本身 - 监控
Seconds_Behind_Master比写一堆 fallback 逻辑更重要;一旦延迟超阈值(比如 > 1s),该拒绝读请求就拒绝,别硬扛
真正的难点从来不在“怎么切”,而在“切了之后敢不敢信这数据”。主库挂了,从库是不是真的 ready,得靠 DBA 的监控和你的业务容忍度一起答。










