You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Laravel 8 运行时全局切换数据库连接,GET请求走只读库方案不生效

Laravel 8 读写连接自动切换中间件解决方案

问题原因

你之前尝试的方案不生效,核心是Laravel会将首次解析的数据库连接实例缓存在容器中,仅修改默认连接配置不会清除已实例化的连接,因此还是会复用之前的主库连接。

前置配置检查

首先确认config/database.php中已经正确配置两个数据库连接:

'connections' => [
    // 主库连接(写)
    'mysql' => [
        'driver' => 'mysql',
        'host' => env('DB_HOST', '127.0.0.1'),
        'port' => env('DB_PORT', '3306'),
        'database' => env('DB_DATABASE', 'forge'),
        'username' => env('DB_USERNAME', 'forge'),
        'password' => env('DB_PASSWORD', ''),
        'unix_socket' => env('DB_SOCKET', ''),
        'charset' => 'utf8mb4',
        'collation' => 'utf8mb4_unicode_ci',
        'prefix' => '',
        'strict' => true,
        'engine' => null,
    ],
    // 只读从库连接(读)
    'mysql_readonly' => [
        'driver' => 'mysql',
        'host' => env('DB_READ_HOST', '127.0.0.1'),
        'port' => env('DB_PORT', '3306'),
        'database' => env('DB_DATABASE', 'forge'),
        'username' => env('DB_READ_USERNAME', 'forge'),
        'password' => env('DB_READ_PASSWORD', ''),
        'unix_socket' => env('DB_SOCKET', ''),
        'charset' => 'utf8mb4',
        'collation' => 'utf8mb4_unicode_ci',
        'prefix' => '',
        'strict' => true,
        'engine' => null,
    ],
],

实现步骤

1. 创建中间件

执行命令生成中间件文件:
php artisan make:middleware DbConnectionSwitch

2. 编写中间件逻辑

编辑app/Http/Middleware/DbConnectionSwitch.php文件,内容如下:

<?php

namespace App\Http\Middleware;

use Closure;
use Illuminate\Support\Facades\Config;
use Illuminate\Support\Facades\DB;

class DbConnectionSwitch
{
    public function handle($request, Closure $next)
    {
        $currentDefaultConn = Config::get('database.default');
        // GET请求走只读库,其余请求走主库
        $targetConn = $request->isMethod('GET') ? 'mysql_readonly' : 'mysql';

        if ($currentDefaultConn !== $targetConn) {
            // 清除原有连接缓存,强制使用新配置创建连接
            DB::purge($currentDefaultConn);
            Config::set('database.default', $targetConn);
        }

        // 如需排除部分GET接口走主库,可在此处添加白名单逻辑
        // if (in_array($request->path(), ['api/write-log', 'admin/*'])) {
        //     DB::purge($targetConn);
        //     Config::set('database.default', 'mysql');
        // }

        return $next($request);
    }
}

3. 注册全局中间件

打开app/Http/Kernel.php,将中间件添加到全局中间件数组的最顶部,确保在所有数据库操作执行前生效:

protected $middleware = [
    \App\Http\Middleware\DbConnectionSwitch::class,
    // 原有其他全局中间件保持不变
    // \App\Http\Middleware\TrustProxies::class,
    // \Fruitcake\Cors\HandleCors::class,
    // ...
];

注意事项

  • 只读库账号仅授予SELECT权限,避免误写操作。
  • 不要在GET请求中执行事务操作,事务依赖写权限,会直接报错。
  • 如果Eloquent模型中单独指定了$connection属性,需要自行调整模型的连接逻辑,或者移除$connection属性走默认连接。

内容的提问来源于stack exchange,提问作者Sunny Kumar

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.29 11:06:08