Yii2分库的实现方法

版权声明:猫猫无心 https://blog.csdn.net/qq_18358973/article/details/81393096

    工作遇到了分库的问题,所谓分库,不是单指是用多个数据库,而是将单个数据库拆分成多个逻辑功能平行的库(通俗的举例说就是讲一个数据库拷贝多份,然后分给每个公司客户一个,它们各自用自己的)。废话不多说,下面介绍使用方法,此为本人原创,笔者架构水平经验有限,仅供参考。

    一.首先,需要了解Yii2使用多个数据库的方法

    1.在配置文件中(建议main-local.php)中加上数据库配置:

'components' => [
    //单库
    'db1' => [
            'class' => 'yii\db\Connection',
            'dsn' => 'mysql:host=127.0.0.1;dbname=dbname1',
            'username' => '****',
            'password' => '****',
            'charset' => 'utf8',
    'tablePrefix' => 'tpr_',
    ],
    //单库
    'db2' => [
            'class' => 'yii\db\Connection',
            'dsn' => 'mysql:host=127.0.0.1;dbname=dbname2',
            'username' => '****',
            'password' => '****',
            'charset' => 'utf8',
    'tablePrefix' => 'tpr_',
    ],
]

    2.直接使用的方法:

$Db = \Yii::$app->db1;
$res1 = $Db->createCommand('SELECT * FROM user limit 1')->queryOne();
$Query = new \yii\db\Query();
$res2 = $Query->where(array('id'=>1))->from('user')->limit(1)->one($Db);

    3.使用模型,首先在models目录下建立User.php,示例目录是\common\models\dbname1\:

<?php
namespace common\models\dbname1;

use yii\db\ActiveRecord;

class User extends ActiveRecord{

    public static function getDb(){
        return \Yii::$app->db1;
    }

}

使用方法:

$User = new \common\models\core\User();
$res1 = $User::find()->where(array('id'=>1))->limit(1)->asArray()->one();
$Query = new \yii\db\Query();
$res2 = $Query->where(array('id'=>1))->from($User::tableName())->limit(1)->one($User::getDb());

    二.在使用多个库的情况下再进行分库

    1.首先将配置中的class改为自定义的class,示例的类文件为\common\components\db\MysqlConnection.php:

'components' => [
	//分库
	'db1' => [
		'class' => 'common\components\db\MysqlConnection',
		'dbname' => 'dbname1',
		'charset' => 'utf8',
		'tablePrefix' => 'tpr_',
	],
	//分库
	'db2' => [
		'class' => 'common\components\db\MysqlConnection',
		'dbname' => 'dbname2',
		'charset' => 'utf8',
		'tablePrefix' => 'tpr_',
	],
]

    2.编写MysqlConnection类:

<?php
namespace common\components\db;

class MysqlConnection extends \yii\db\Connection{
    
    public function __construct($config=[]){    //$config为db中配置的参数
        /*
         * 配置生效前的初始化过程
         * 此处与在控制器中一样可以使用yii2中的绝大多数方法和函数
         * 获取数据库及数据库的配置参数
         * 根据$config['dbname']拼接分库名如:$rel_dbname = '201808_'.$config['dbname']
         */
        //mysql的配置参数
        $myconfig['dsn'] = "mysql:host={$host};port={$port};dbname={$rel_dbname}";
        $myconfig['username'] = $username??$config['username'];
        $myconfig['password'] = $password??$config['password'];
        $myconfig['charset'] = $charset??$config['charset'];
        if(isset($config['tablePrefix'])){
            $myconfig['tablePrefix'] = $config['tablePrefix'];
        }
        //实例化数据库连接类
        parent::__construct($myconfig);
    }

}

直接使用的方法:

//使用初始化的连接
$Db1 = \Yii::$app->db1;

//自定义参数的连接,会覆盖配置文件中的参数
$config = array(
    //分库的配置参数,此处的处理逻辑及参数规则需要自己在MysqlConnection.php里编写,这里只给个思路
    'db' => 'db2',  //使用db2的配置参数
    'fk_config' => array(
        'val1' => '****',
        'val3' => '****',
        'val3' => '****',
    )
);
$Db2 = new \common\components\db\MysqlConnection($config);

    3.在模型中使用,先修改模型文件User.php

namespace common\models\dbname1;

use yii\db\ActiveRecord;

class User extends ActiveRecord{
         
    protected static $myconfig;
    
    function __construct($config = array()){
        if($config){    //如果有自定义参数
            self::$myconfig['fk_config'] = $config;
        }
        parent::__construct();
    }

    public static function getDb(){
        if(self::$myconfig){    //处理自定义参数
            self::$myconfig['db'] = 'db1';
            return new \common\components\db\MysqlConnection(self::$myconfig);
        }else{
            return \Yii::$app->db_core;
        }
    }

}

使用方法:

//使用初始化的参数
$User = new \common\models\dbname1\User();

//自定义参数的模型,会覆盖配置文件中的参数
$fk_config = array(
    //分库的配置参数,此处的处理逻辑及参数规则需要自己在MysqlConnection.php里编写,这里只给个思路
    'val1' => '****',
    'val3' => '****',
    'val3' => '****',
);
$User = new \common\models\dbname1\User($fk_config);

其实每个数据表模型中都要写__construct()和getDb()是不太合理的,可以写个通用模型作为父类写入__construct()和getDb(),然后数据表模型继承此模型即可,笔者就是这么做的但没有写出来,因为写出来会增加阅读和理解难度,读者可以自己去尝试。

猜你喜欢

转载自blog.csdn.net/qq_18358973/article/details/81393096
今日推荐