ThinkPHP框架分布式数据库连接方法详解


Posted in PHP onMarch 14, 2017

本文实例分析了ThinkPHP框架分布式数据库连接方法。分享给大家供大家参考,具体如下:

Thinkphp作为国内的一款流行框架,相信使用的人一定不在少数。本篇我们来分析一下Thinkphp中比较重要的一部分——分布式数据库的连接。

当然了,我们在这里不是去将如何使用模型去对数据库进行增删改查。我们是对其底层的连接代码做一个分析,可以帮助大家更好的理解thinkphp对数据库的操作。方便我们以后的使用。

一、单一数据库的连接

在使用的时候,单一数据库的连接配置非常简单。我们只需要在配置文件中配置一下的信息即可。

'DB_TYPE' => 'mysql',
'DB_HOST' => '192.168.5.102',
'DB_NAME' => 'databasename',
'DB_USER' => 'user',
'DB_PWD' => 'password',
'DB_PORT' => '3306',
'DB_PREFIX' => 'onmpw_',

设置完成以后就可以使用了。默认情况下就是单一的数据库连接。

二、分布式数据库的连接

单一数据库的连接很简单,我们着重分析一下分布式数据库的连接。

'DB_TYPE' => 'mysql',
'DB_HOST' => '192.168.5.191,192.168.5.88,192.168.5.103',
'DB_NAME' => 'test,test,test',
'DB_USER' => 'masteruser,slaveuser,slaveuser',
'DB_PWD' => 'masterpass,slavepass,slavepass',
'DB_PORT' => '3306',
'DB_PREFIX' => '',
'DB_DEPLOY_TYPE' => 1, // 数据库部署方式:0 集中式(单一服务器),1 分布式(主从服务器)
'DB_RW_SEPARATE' => true, // 数据库读写是否分离 主从式有效
'DB_MASTER_NUM' => 1, // 读写分离后 主服务器数量
'DB_SLAVE_NO' => '', // 指定从服务器序号

按照以上配置就可以连接分布式数据库了。

下面我们看下面几个选项

'DB_HOST'

分布式数据库,有几台服务器就要填写几个服务器地址,每个地址之间用逗号隔开。如果是主从式分布的话,前面的地址要是主数据库的地址。

对于下面的用户名和密码还有监听端口之类的,当然是有几个就写几个。如果各个数据库的用户名和密码都一样的话,可以只写一个。

对于这些选项的解析的代码如下

$_config['username'] =  explode(',',$this->config['username']);
$_config['password'] =  explode(',',$this->config['password']);
$_config['hostname'] =  explode(',',$this->config['hostname']);
$_config['hostport']  =  explode(',',$this->config['hostport']);
$_config['database'] =  explode(',',$this->config['database']);
$_config['dsn']   =  explode(',',$this->config['dsn']);
$_config['charset']  =  explode(',',$this->config['charset']);

'DB_DEPLOY_TYPE'=>1

1 表示是分布式, 0 表示的是集中式(也就是单一服务器)。

该选项的实现是在类 Think\Db\Dirver中

protected function initConnect($master=true) {
  if(!empty($this->config['deploy']))
    // 采用分布式数据库
    $this->_linkID = $this->multiConnect($master);
  else
    // 默认单数据库
    if ( !$this->_linkID ) $this->_linkID = $this->connect();
}

$this->config['deploy']表示的就是'DB_DEPLOY_TYPE'这个配置选项,上面的配置在使用之前都已经经过解析了,配置项都在$this->config数组中。至于是如何解析配置文件的,这里我们不做介绍,感兴趣的可以参考Think\Db类。

$this->multiConnect()函数就是用来进行分布式连接的,如果'DB_DEPLOY_TYPE'选项设置为1,该函数就会执行。否则直接执行$this->connect()函数。

'DB_RW_SEPARATE'=>true

true 表示读写分离;false表示读写不分离。

这里需要注意的是,读写分离是以主从式数据库系统为前提的。该选项设置为true的时候主数据库写,从数据库读。

if($this->config['rw_separate']){
   // 主从式采用读写分离
   if($master)
     // 主服务器写入
     $r =  $m;
   else{
     if(is_numeric($this->config['slave_no'])) {// 指定服务器读
       $r = $this->config['slave_no'];
     }else{
        // 读操作连接从服务器
       $r = floor(mt_rand($this->config['master_num'],count($_config['hostname'])-1));  // 每次随机连接的数据库
     }
      }
}else{
   // 读写操作不区分服务器
   $r = floor(mt_rand(0,count($_config['hostname'])-1));  // 每次随机连接的数据库
}

$this->config['rw_separate'] 为true的时候采用读写分离,为false的时候读写不分离。读写分离为什么必须是主从式的呢?因为从服务器不能写只能读,如果向从服务器写入数据的话,数据是没法同步的。这样就会造成数据不一致的情况。所以说,如果我们的系统是主从式的话,我们必须采用读写分离。也就是说DB_RW_SEPARATE选项必须配置为true。

'DB_MASTER_NUM'=>1

该选项后面的数字表示读写分离后,主服务器的数量。因此该选项也是用于主从式数据库系统。

下面的代码是选择主服务器。

$m = floor(mt_rand(0,$this->config['master_num']-1));

主从式数据库读取的时候选择从服务器读的核心代码

$r = floor(mt_rand($this->config['master_num'],count($_config['hostname'])-1));   // 每次随机连接的数据库

其中$this->config['master_num']表示主服务器的数量。

'DB_SLAVE_NO'=> ''

指定从服务器的序号,用于读取数据。如果不设置,则根据主服务器的数量计算书从服务器的数量,然后从中随机选取一台进行读取。

if(is_numeric($this->config['slave_no'])) {// 指定服务器读
  $r = $this->config['slave_no'];
}else{
  // 读操作连接从服务器
  $r = floor(mt_rand($this->config['master_num'],count($_config['hostname'])-1));  // 每次随机连接的数据库
}

以上是对每个选项的作用的实现代码进行了一个简单的说明。

下面我们来看其连接的部分

if($m != $r ){
  $db_master = array(
   'username' => isset($_config['username'][$m])?$_config['username'][$m]:$_config['username'][0],
   'password' => isset($_config['password'][$m])?$_config['password'][$m]:$_config['password'][0],
   'hostname' => isset($_config['hostname'][$m])?$_config['hostname'][$m]:$_config['hostname'][0],
   'hostport' => isset($_config['hostport'][$m])?$_config['hostport'][$m]:$_config['hostport'][0],
   'database' => isset($_config['database'][$m])?$_config['database'][$m]:$_config['database'][0],
   'dsn' => isset($_config['dsn'][$m])?$_config['dsn'][$m]:$_config['dsn'][0],
   'charset' => isset($_config['charset'][$m])?$_config['charset'][$m]:$_config['charset'][0],
  );
}
$db_config = array(
  'username' => isset($_config['username'][$r])?$_config['username'][$r]:$_config['username'][0],
  'password' => isset($_config['password'][$r])?$_config['password'][$r]:$_config['password'][0],
  'hostname' => isset($_config['hostname'][$r])?$_config['hostname'][$r]:$_config['hostname'][0],
  'hostport' => isset($_config['hostport'][$r])?$_config['hostport'][$r]:$_config['hostport'][0],
   'database' => isset($_config['database'][$r])?$_config['database'][$r]:$_config['database'][0],
   'dsn' => isset($_config['dsn'][$r])?$_config['dsn'][$r]:$_config['dsn'][0],
   'charset'  => isset($_config['charset'][$r])?$_config['charset'][$r]:$_config['charset'][0],
);
return $this->connect($db_config,$r,$r == $m ? false : $db_master);

看到这,我觉得大家应该对上面在介绍各个配置选项的代码的时候其中的$r和$m是什么作用了。

现在我们来看 $r == $m ? false : $db_master ,如果数据库读写不分离的情况下,读写是一台服务器的话 传给connect函数的值为false。或者是如果是主从分离的写的情况下传给connect的值也为false。通过上面代码我们看到,如果$r和$m不相等的情况下,会设置$db_master。其实也就是相当于一台备用的,如果选择的$r服务器出现故障不能连接,将会去连接$db_master。

connect()函数的第三个参数其实是表示当$db_config这台服务器连接故障时是否选择备用的连接。false表示不重连,其它值即表示重新连接。

其核心代码如下

try{
  if(empty($config['dsn'])) {
   $config['dsn'] =  $this->parseDsn($config);
  }
  if(version_compare(PHP_VERSION,'5.3.6','<=')){
    // 禁用模拟预处理语句
    $this->options[PDO::ATTR_EMULATE_PREPARES] =  false;
  }
  $this->linkID[$linkNum] = new PDO( $config['dsn'], $config['username'], $config['password'],$this->options);
}catch (\PDOException $e) {
  if($autoConnection){ //$autoConnection不为false,而是默认的主服务器
    trace($e->getMessage(),'','ERR');
      return $this->connect($autoConnection,$linkNum); //出现异常,使用递归函数重新连接
    }elseif($config['debug']){
      E($e->getMessage());
  }
}

这种方式,对于主从式来说,$r和$m肯定不会相同。因此如果说在读取数据的时候,选择的那台从服务器出现故障的话,那主服务器即是备用的,最后会去主服务器读取。能保证数据读取的时效性。

但是,总感觉现在还不太完善。如果说有多台从服务器,在读取的时候选择的那台从服务器和主服务器都出现了故障,那数据岂不是就读取失败了。这时候如果能再次读取其它的从服务器的话那应该是更有保障。当然了,目前的thinkphp的功能已经相当完善,足够我们使用了。但是还是希望thinkphp以后越来越完善。

希望本文所述对大家基于ThinkPHP框架的PHP程序设计有所帮助。

PHP 相关文章推荐
php在字符串中查找另一个字符串
Nov 19 PHP
Cakephp 执行主要流程
Mar 24 PHP
很让人受教的 提高php代码质量36计
Sep 05 PHP
PHP关于htmlspecialchars、strip_tags、addslashes的解释
Jul 04 PHP
php命令行(cli)下执行PHP脚本文件的相对路径的问题解决方法
May 25 PHP
php中动态变量用法实例
Jun 10 PHP
Symfony2之session与cookie用法小结
Mar 18 PHP
PHP实现无限分类的实现方法
Nov 14 PHP
PHP根据树的前序遍历和中序遍历构造树并输出后序遍历的方法
Nov 10 PHP
PHP中使用CURL发送get/post请求上传图片批处理功能
Oct 15 PHP
使用PHPUnit进行单元测试并生成代码覆盖率报告的方法
Mar 08 PHP
thinkphp5实现微信扫码支付
Dec 23 PHP
让ThinkPHP的模板引擎达到最佳效率的方法详解
Mar 14 #PHP
thinkphp3.2实现跨控制器调用其他模块的方法
Mar 14 #PHP
Yii2下点击验证码的切换实例代码
Mar 14 #PHP
php分页查询的简单实现代码
Mar 14 #PHP
php实现购物车产品删除功能(2)
Jul 23 #PHP
php实现产品加入购物车功能(1)
Jul 23 #PHP
浅谈PHP的排列组合(如输入a,b,c 输出他们的全部组合)
Mar 14 #PHP
You might like
如何使用Linux的Crontab定时执行PHP脚本的方法
2011/12/19 PHP
深入php-fpm的两种进程管理模式详解
2013/06/03 PHP
如何给phpcms v9增加类似于phpcms 2008中的关键词表
2013/07/01 PHP
php 数组元素快速去重
2017/05/05 PHP
PHP长网址与短网址的实现方法
2017/10/13 PHP
laravel 之 Eloquent 模型修改器和序列化示例
2019/10/17 PHP
EASYUI TREEGRID异步加载数据实现方法
2012/08/22 Javascript
js跳转页面方法总结
2014/01/29 Javascript
js控件Kindeditor实现图片自动上传功能
2020/07/20 Javascript
AngularJS表格样式简单设置方法示例
2017/03/03 Javascript
关于Angularjs中自定义指令一些有价值的细节和技巧小结
2018/04/22 Javascript
vue src动态加载请求获取图片的方法
2018/10/17 Javascript
nuxt中使用路由守卫的方法步骤
2019/01/27 Javascript
vue中监听路由参数的变化及方法
2019/12/06 Javascript
解决Vue 刷新页面导航显示高亮位置不对问题
2019/12/25 Javascript
[47:42]完美世界DOTA2联赛PWL S2 GXR vs Ink 第一场 11.19
2020/11/20 DOTA
python实现数通设备端口监控示例
2014/04/02 Python
python中global用法实例分析
2015/04/30 Python
Python使用正则表达式获取网页中所需要的信息
2018/01/29 Python
如何在Django中添加没有微秒的 DateTimeField 属性详解
2019/01/30 Python
对Django中内置的User模型实例详解
2019/08/16 Python
Python matplotlib以日期为x轴作图代码实例
2019/11/22 Python
如何基于python3和Vue实现AES数据加密
2020/03/27 Python
Django更新models数据库结构步骤
2020/04/01 Python
Python-jenkins模块获取jobs的执行状态操作
2020/05/12 Python
Python 操作 MySQL数据库
2020/09/18 Python
python实现杨辉三角的几种方法代码实例
2021/03/02 Python
Spanx塑身衣官网:美国知名内衣品牌
2017/01/11 全球购物
日本7net购物网:书籍、漫画、杂志、DVD、游戏邮购
2017/02/17 全球购物
英国工作场所设备购买网站:Slingsby
2019/05/03 全球购物
家长对孩子评语
2014/01/30 职场文书
道德之星事迹材料
2014/05/03 职场文书
党员对照检查材料思想汇报
2014/09/16 职场文书
部门优秀员工推荐信
2015/03/24 职场文书
最新农村养殖致富:资金投入较低的创业项目有哪些?
2019/09/26 职场文书
JavaScript canvas实现流星特效
2021/05/20 Javascript