在队列中动态切换MySQL数据源,会导致数据串库

1. 运行环境

LNMP

1). 当前使用的 Laravel 版本?

8.12

2). 当前使用的 php/php-fpm 版本?

PHP 版本:7.4

3). 当前系统

CentOS

4). 业务环境

开发环境,单节点未使用负载均衡

5). 相关软件版本

MySQL8.0

2. 问题描述?

系统是一个多租户的Saas系统,存在多数据库,需要根据用户切换数据源,同步请求时是正常的,当采用redis异步队列的时候,切换数据源后,执行异步操作,会发生串库现象。config()->set没有生效。

//对列中修改数据库的配置
            config()->set('database.connections.mysql_master.host', $dbConfig['host']);
            config()->set('database.connections.mysql_master.port', $dbConfig['port']);
            config()->set('database.connections.mysql_master.database', $dbConfig['database']);
            config()->set('database.connections.mysql_master.username', $dbConfig['username']);
            config()->set('database.connections.mysql_master.password', $dbConfig['password']);
            $this->connection = 'mysql_master';

在队列中动态切换MySQL数据源,会导致数据串库

3. 您期望得到的结果?

异步队列内切换数据库成功,写入对应的数据库

4. 您实际得到的结果?

队列内业务部分写到目标库,部分写到其它数据库,发生串库问题。

《L03 构架 API 服务器》
你将学到如 RESTFul 设计风格、PostMan 的使用、OAuth 流程,JWT 概念及使用 和 API 开发相关的进阶知识。
《L02 从零构建论坛系统》
以构建论坛项目 LaraBBS 为线索,展开对 Laravel 框架的全面学习。应用程序架构思路贴近 Laravel 框架的设计哲学。
讨论数量: 6

我目前这个项目也像是saas 我是同一个数据库 然后这个下面分不同的库名 用户名密码是一样 只需要切换一下库 然后 封装了一个switch_database去切换库
每次在队列中间件里面做一次切换

if (!function_exists('switch_database')) {
    /**
     * 切換庫
     *
     * @param string $idCode
     * @return void
     */
    function switch_database(string $idCode): void
    {
        context_store()->setIdCode($idCode);

        // 獲取數據庫所有連接
        $connections = DB::getConnections();

        // 如果不存在這個數據庫連接 則不切換庫 會在第一次建立這個連接的時候會觸發事件 切換到對應的庫
        if (!isset($connections[DB::getDefaultConnection()])) {
            return;
        }

        $databaseName = get_database_name($idCode);

        DB::statement("use $databaseName");
        DB::setDatabaseName($databaseName);
    }
}
<?php

namespace App\Jobs\Middleware;

use App\Jobs\BaseJob;
use Closure;

class ContextTrace
{
    public function handle(object $job, Closure $next): void
    {
        /** @var BaseJob $job */
        log_share_context_uuid($job->contextTraceId);
        switch_database($job->idCode);

        $next($job);
    }
}

Laravel

所有job都继承者baseJob

10个月前 评论

断开当前链接再链接新的库

10个月前 评论

你这样改肯定不行 DB是单例 你第一次的运行的时候就已经实例化对应的驱动了 你第二次去用的时候直接拿这个实例了 不会初始化了 你配置完这个后 需要DB::reconnect() 重置连接一下

10个月前 评论

我目前这个项目也像是saas 我是同一个数据库 然后这个下面分不同的库名 用户名密码是一样 只需要切换一下库 然后 封装了一个switch_database去切换库
每次在队列中间件里面做一次切换

if (!function_exists('switch_database')) {
    /**
     * 切換庫
     *
     * @param string $idCode
     * @return void
     */
    function switch_database(string $idCode): void
    {
        context_store()->setIdCode($idCode);

        // 獲取數據庫所有連接
        $connections = DB::getConnections();

        // 如果不存在這個數據庫連接 則不切換庫 會在第一次建立這個連接的時候會觸發事件 切換到對應的庫
        if (!isset($connections[DB::getDefaultConnection()])) {
            return;
        }

        $databaseName = get_database_name($idCode);

        DB::statement("use $databaseName");
        DB::setDatabaseName($databaseName);
    }
}
<?php

namespace App\Jobs\Middleware;

use App\Jobs\BaseJob;
use Closure;

class ContextTrace
{
    public function handle(object $job, Closure $next): void
    {
        /** @var BaseJob $job */
        log_share_context_uuid($job->contextTraceId);
        switch_database($job->idCode);

        $next($job);
    }
}

Laravel

所有job都继承者baseJob

10个月前 评论

把业务写在service 就不会了 , 让job 减负

10个月前 评论

动态修改配置前先断开连接,一定要用purge方法,disconnect方法并不会清楚缓存的实例

DB::purge('mysql_master');
10个月前 评论

可不可以将 database 甚至 config 放到 consul 中去?

10个月前 评论

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!