数据库切换

优质
小牛编辑
133浏览
2023-12-01

简介

在 Swoft 2.0.2 版本之前,连接池中没有数据库切换功能,这导致了不同数据库需要配置多个连接池,大大增加了维护成本。所以在 2.0.2 开始新增了切换数据库功能。你可以在链式操作中使用 db() 方法进行指定,这显然不够灵活难以维护,下面推荐一个根据上下文切换数据的操作。

Swoft 版本需 >= 2.0.2

DbSelector

实现

使用 DbSelector 需实现 Swoft\Db\Contract\DbSelectorInterface 接口:

<?php declare(strict_types=1);

namespace App\Common;

use Swoft\Bean\Annotation\Mapping\Bean;
use Swoft\Db\Connection\Connection;
use Swoft\Db\Contract\DbSelectorInterface;

/**
 * Class DbSelector
 *
 * @since 2.0
 *
 * @Bean()
 */
class DbSelector implements DbSelectorInterface
{
    /**
     * @param Connection $connection
     */
    public function select(Connection $connection): void
    {
        // 在请求中获取 ID
        $selectIndex = (int)context()->getRequest()->query('id', 0);
        $createDbName = $connection->getDb();

        if ($selectIndex == 0) {
            $selectIndex = '';
        }
        // 数据库名 + ID。例如:order_database_1,好处是会根据上下文自动切库
        $dbName = sprintf('%s%s', $createDbName, (string)$selectIndex);
        $connection->db($dbName);
    }
}

配置

实现 DbSelector 后,还需在 bean.php 中定义 dbSelector 属性,例如:

'db2' => [
    'dsn'        => 'mysql:dbname=test;host=127.0.0.1:3306',
    'username'   => 'root',
    'password'   => '123456',
    'dbSelector' => bean(App\Common\DbSelector::class)
],
'db2.pool' => [
    'database' => bean('db2')
]

通过在 db 中添加 dbSelector 属性以指定实现类。之后每次操作均会调用该类自动切换数据库。使用这种方式后大大降低了维护成本,官方推荐

其它说明

如果 DbSelector 的方式无法满足需求时,仅能通过 db 方法手动指定数据库。

// 模型类
User::db('test2')->insertGetId([
    'name'      => uniqid(),
    'password'  => md5(uniqid()),
    'age'       => mt_rand(1, 100),
    'user_desc' => 'Swoft'
]);

// DB 方式       
DB::table('user')->db('test2')->insertGetId([
    'name'      => uniqid(),
    'password'  => md5(uniqid()),
    'age'       => mt_rand(1, 100),
    'user_desc' => 'Swoft Framework'
]);

不推荐该方式,使用 db 方法会加大维护成本,且容错率低。