Lumen/laravel动态分库的实现

阅读更多
lumen默认支持多数据源,但如果系统存在多个结构相同的数据库实例,并根据某特定请求参数访问不同的实例,那么可以通过中间件实现动态配置。

1、在app/config/database.php文件中配置默认mysql数据库连接参数
2、在默认库中创建一个配置表,其中保存各数据库分库的配置,如下表(以corpid做分库条件),这个表只需要在主库中创建并维护
引用

CREATE TABLE `corp_database` (
  `corpid` varchar(50) NOT NULL DEFAULT '' COMMENT '租户id',
  `read_host` varchar(100) NOT NULL DEFAULT '' COMMENT '读库地址',
  `read_port` int(11) NOT NULL DEFAULT '3306' COMMENT '读库端口',
  `read_database` varchar(100) NOT NULL DEFAULT '' COMMENT '读库数据库名',
  `read_user` varchar(100) NOT NULL DEFAULT '' COMMENT '读库用户',
  `read_password` varchar(100) NOT NULL DEFAULT '' COMMENT '读库密码',
  `write_host` varchar(100) NOT NULL DEFAULT '' COMMENT '写库地址',
  `write_port` int(11) NOT NULL DEFAULT '3306' COMMENT '写库端口',
  `write_database` varchar(100) NOT NULL DEFAULT '' COMMENT '写库数据库名',
  `write_user` varchar(100) NOT NULL DEFAULT '' COMMENT '写库用户',
  `write_password` varchar(100) NOT NULL DEFAULT '' COMMENT '写库密码',
  `driver` varchar(100) NOT NULL DEFAULT 'mysql' COMMENT '驱动名称',
  `charset` varchar(100) NOT NULL DEFAULT 'utf8' COMMENT '字符集',
  `collation` varchar(100) NOT NULL DEFAULT 'utf8_unicode_ci',
  `prefix` varchar(100) NOT NULL DEFAULT '' COMMENT '数据表前缀',
  `timezone` varchar(100) NOT NULL DEFAULT '+00:00' COMMENT '时区',
  `strict` varchar(10) NOT NULL DEFAULT 'false' COMMENT '是否执行严格模式',
  PRIMARY KEY (`corpid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

3、创建一个corp_database的model类
class CorpDatabaseModel extends BaseModel{

	private $table = 'corp_database';
	public function  __construct(){
		parent::__construct();
		
	}
	
	public function  get($corpid){
	
		if(!$corpid){
			return null;
		}
		
		return app('db')->table($this->table)->where('corpid',$corpid)->first();
		
	}

    public function  getAndFormat($corpid){

        if(!$corpid){
            return null;
        }

        $r = app('db')->table($this->table)->where('corpid',$corpid)->first();
        if($r) {
            $result['read']['host'] = $r['read_host'];
            $result['read']['port'] = $r['read_port'];
            $result['read']['database'] = $r['read_database'];
            $result['read']['username'] = $r['read_username'];
            $result['read']['password'] = $r['read_password'];
            $result['write']['host'] = $r['write_host'];
            $result['write']['port'] = $r['write_port'];
            $result['write']['database'] = $r['write_database'];
            $result['write']['username'] = $r['write_username'];
            $result['write']['password'] = $r['write_password'];
            $result['driver'] = $r['driver'];
            $result['charset'] = $r['charset'];
            $result['collation'] = $r['collation'];
            $result['prefix'] = $r['prefix'];
            $result['timezone'] = $r['timezone'];
            $result['strict'] = $r['strict'];
            return $result;
        } else {
            return null;
        }
    }

    /**
     * @param $save_array
     * @return mixed
     */
    public function save($save_array){

        return app('db')->db()->table($this->table)->insertGetId($save_array);

    }

    public function modifyById($id, $data =array()){
        if(!$id){
            return 0;
        }
        if(!count($data)){
            return 0;
        }
        return app('db')->db()->table($this->table)->where('coprid',$id)->update($data);
    }
}

4、在app/Http/Middleware/xxxMiddleware.php(自行在routes.php中配置生效)中添加以下代码
……
public function handle($request, Closure $next) {
        $corpId = $request->get('corpid', '');
        if($corpId) {
            $corpDatabaseModel = new CorpDatabaseModel();
            $dbConfig = $corpDatabaseModel->getAndFormat($corpId);
            if($dbConfig) {
                config(['database.connections.' . $corpId => $dbConfig]);
                config(['database.default' => $corpId]);
            }
        }
……
}
……

5、通过中间件修改数据库组件的默认链接名称实现动态分库。这样内部代码不需要做任何特殊处理即可实现对不同数据库分库的访问。

你可能感兴趣的:(Lumen/laravel动态分库的实现)