2019独角兽企业重金招聘Python工程师标准>>>

以前做PHP应用,多数是单数据库数据查询和更新,顶多也是主从数据库的支持,实现起来相对简单。主从数据库的问题在于,当会话存储在数据库的时候,同步将可能出现问题,也就是说有可能出现会话的中断。所以我想在主从数据库设计上,应该将所有会话相关表进行特殊对待。即:所有的会话数据表都可以更新和查询,当一个用户访问站点的时候,即将此用户绑定到指定数据库,所有会话访问和查询操作都对此数据库进行。会话表不做同步,其他非会话类更新也从主数据库更新。这样做其实也逃脱不了会话更新时候的数据库切换,所以如果不想麻烦,还是将会话存放在文本中进行的好。
分数据库设计,将可能从压力性能上会提升几个档次,当然单次执行效率不会比单数据库来的高的,毕竟存在着数据库切换的效率问题。分库以及主从数据库搭配是可以比较好改善数据库并发瓶颈的方案。原则:大数据量,分库;大访问量,主从。很多时候,都是这两者并行(本文不讨论cache)。
我想,如果要实现分库以及主从关系,那么数据库服务器数量将是非常可观,在应用程序中随时切换到某一台服务器,将是非常头痛的问题,配置更换,变量名称,是不是会有一大堆呢?如何寻找更好的解决方案将是本文谈论的话题。
首先是分库使得数据库颇多的问题。什么情况下分库?或许有些人还搞不明白为什么要分库,我就简要说一下自己的经验猜测。比如一个博客程序,一般设计是将日志存放在一张日志表中。假设是一个多用户博客,那么将会关联一个uid,如果数据量不大,这样设计是没有问题的,但是当日志量巨大,一天有几十万条日志记录录入的时候,而且访问量也比较可观的时候,我想不可能每个用户来访问日志列表,都去从这包含几千万条日志记录的数据表中去找那么几条,效率可见一斑。这个时候就该考虑到分库的问题。如何分?有一个很简单的分表方法,即,根据uid段,将日志记录在各个数据库中,当然,这个分布还是需要根据以往统计结果做出调整的,因为用户日志分布肯定不是均匀的。设置好uid段,然后根据uid索引到指定数据库配置,创建一个数据库对象即可。配置信息可能如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
$configs [ 'db_info' ][ 'blog' ][0] = array (
     'db_host' => '192.168.0.1' ,
     'db_name' => 'blog' ,
     'db_user' => 'root' ,
     'db_pass' => '' ,
);
$configs [ 'db_info' ][ 'blog' ][1] = array (
     'db_host' => '192.168.0.2' ,
     'db_name' => 'blog' ,
     'db_user' => 'root' ,
     'db_pass' => '' ,
);
$configs [ 'db_info' ][ 'blog' ][2] = array (
     'db_host' => '192.168.0.2' ,
     'db_name' => 'blog' ,
     'db_user' => 'root' ,
     'db_pass' => '' ,
);
//...还有很多

至于选择哪一台服务器,只需要根据uid做一个简单的匹配就可以了。
再谈到的就是主从数据库了。什么情况下使用主从数据库?比如某个名人博客,访问量相当的大,已经没有办法把他的数据再进行拆分了,这个时候就得考虑主从数据库服务器了,使用多台数据库来分流。这样要适用主从和分库,可能上面配置信息得稍微改动一下。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
$configs [ 'db_info' ][ 'blog' ][0][ 'master' ] = array (
     'db_host' => '192.168.0.1' ,
     'db_name' => 'blog' ,
     'db_user' => 'root' ,
     'db_pass' => '' ,
);
$configs [ 'db_info' ][ 'blog' ][0][ 'slave' ][0] = array (
     'db_host' => '192.168.0.2' ,
     'db_name' => 'blog' ,
     'db_user' => 'root' ,
     'db_pass' => '' ,
);
$configs [ 'db_info' ][ 'blog' ][0][ 'slave' ][1] = array (
     'db_host' => '192.168.0.3' ,
     'db_name' => 'blog' ,
     'db_user' => 'root' ,
     'db_pass' => '' ,
);
$configs [ 'db_info' ][ 'blog' ][1][ 'master' ] = array (
     'db_host' => '192.168.0.4' ,
     'db_name' => 'blog' ,
     'db_user' => 'root' ,
     'db_pass' => '' ,
);
$configs [ 'db_info' ][ 'blog' ][1][ 'slave' ][0] = array (
     'db_host' => '192.168.0.5' ,
     'db_name' => 'blog' ,
     'db_user' => 'root' ,
     'db_pass' => '' ,
);
$configs [ 'db_info' ][ 'blog' ][1][ 'slave' ][1] = array (
     'db_host' => '192.168.0.6' ,
     'db_name' => 'blog' ,
     'db_user' => 'root' ,
     'db_pass' => '' ,
);
$configs [ 'db_info' ][ 'session' ][0][ 'master' ] = array (
     'db_host' => '192.168.0.7' ,
     'db_name' => 'session' ,
     'db_user' => 'root' ,
     'db_pass' => '' ,
);
$configs [ 'db_info' ][ 'session' ][1][ 'master' ] = array (
     'db_host' => '192.168.0.8' ,
     'db_name' => 'session' ,
     'db_user' => 'root' ,
     'db_pass' => '' ,
);

写到这里,我想都应该知道如何分表和分配你的数据库了吧,接下去我就来说一下如何轻松的读取这样的配置信息,如何将这些配置融入你的数据库驱动中。首先以单例摸式创建DB类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
<?php
if (!defined( "DB_FETCH_ASSOC" )) {
     define( "DB_FETCH_ASSOC" , 1);
}
  
if (!defined( "DB_FETCH_ROW" )) {
     define( "DB_FETCH_ROW" , 2);
}
  
if (!defined( "DB_FETCH_ARRAY" )) {
     define( "DB_FETCH_ARRAY" , 3);
}
  
if (!defined( "DB_FETCH_DEFAULT" )) {
     define( "DB_FETCH_DEFAULT" , DB_FETCH_ASSOC);
}
class DB {
     function DB( $dsn , $db_key , $p_conn , $fetch_mode ) {
         $this ->dsn        = $dsn ;
         $this ->db_key     = $db_key ;
         $this ->sql        = '' ;
         $this ->sqls       = array ();
         $this ->u_sqls     = array ();
         $this ->q_sqls     = array ();
         $this ->u_conn     = null;
         $this ->q_conn     = null;
         $this ->p_conn     = $p_conn ;
         $this ->fecth_mode = $fetch_mode ;
         $this ->query_num  = 0;
         $this ->update_num = 0;
     }
  
     function &init(& $dsn , $db_key , $p_conn = false, $fetch_mode = DB_FETCH_DEFAULT) {
         static $db ;
         $db_key = explode ( '.' , $db_key );
         $db_key = "['" . implode( "']['" , $db_key ) . "']" ;
         eval ( '$flag = isset($db' . $db_key . ');' );
         eval ( "$db_info = $dsn['db_info']" . $db_key . ";" );
         if (! $flag ) {
             $obj = new DB( $db_info , $db_key , $p_conn , $fetch_mode );
             eval ( '$db' . $db_key . ' = $obj;' );
             unset( $obj );
         }
         return $db ;
     }
}
$db = &DB::init( $configs , 'blog.0' );
print_r( $db );
?>

从上面打印结果可以看出,blog数据库集群的第一组数据库服务器被载入到$this->dsn中了。这个下面就是简单的数据COPY的主从服务器,所以可以使用随机数来指定到某一台服务器。以下是一个简单的随机数实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
class DB {
     //....
  
     function connectDB( $type = "master" ) {
         if ( $type == "master" ) {
             $db_host = $this ->dsn[ "master" ][ "db_host" ];
             $db_name = $this ->dsn[ "master" ][ "db_name" ];
             $db_user = $this ->dsn[ "master" ][ "db_user" ];
             $db_pass = $this ->dsn[ "master" ][ "db_pass" ];
             $this ->u_conn = mysqli_connect( $db_host , $db_user , $db_pass );
             $this ->selectDB( $db_name , $this ->conn);
             if (! $this ->u_conn) {
                 $message = "Update DataBase Connect False : ($db_host, $db_user, ******) !" ;
                 $this ->error( $message , 0);
             }
         } else {
             if ( empty ( $_COOKIE [ $_configs [ 'cookie_prefix' ] . 'db_no' ])) {
                 $db_no = array_rand ( $this ->dsn[ "db_info" ][ "slave" ]);
             } else {
                 $db_no = $_COOKIE [ $_configs [ 'cookie_prefix' ] . 'db_no' ];
             }
             $db_info = $this ->dsn[ "slave" ][ $db_no ];
             $db_host = $db_info [ "db_host" ];
             $db_name = $db_info [ "db_name" ];
             $db_user = $db_info [ "db_user" ];
             $db_pass = $db_info [ "db_pass" ];
             $this ->q_conn = mysqli_connect( $db_host , $db_user , $db_pass );
  
             if (! $this ->q_conn) {
                 if (! $this ->u_conn) {
                     $this ->connectDB();
                 }
                 $this ->q_conn = $this ->u_conn;
                 if (! $this ->q_conn) {
                     $message = "Query DataBase Connect False : ($db_host, $db_user, ******) !" ;
                     $this ->error( $message , 0);
                 }
             } else {
                 $this ->selectDB( $db_name , $this ->q_conn);
             }
         }
     }
  
     function selectDB( $db_name , $conn ) {
         if ( $db_name != null) {
             if (! mysqli_select_db( $conn , $db_name )) {
                 $code = mysqli_errno( $conn );
                 $message = mysqli_error( $conn );
                 $this ->error( $message , $code );
             }
             return true;
         }
         return false;
     }
  
     function query( $sql , $limit = 1, $quick = false) {
         if ( $limit != null) {
             $sql = $sql . " LIMIT " . $limit ;
         }
         $this ->sqls[] = $sql ;
         $this ->q_sqls[] = $sql ;
         $this ->sql = $sql ;
  
         if ( empty ( $this ->q_conn)) {
             $this ->connectDB( "slave" );
         }
         $this ->qrs = mysqli_query( $this ->q_conn, $sql , $quick ? MYSQLI_USE_RESULT : MYSQLI_STORE_RESULT);
         if (! $this ->qrs) {
             $code = mysqli_errno( $this ->q_conn);
             $message = mysqli_error( $this ->q_conn);
             $this ->error( $message , $code );
         }
         $this ->query_num++;
         return $this ->qrs;
     }
  
     function update( $sql ) {
         $this ->sql = $sql ;
         $this ->sqls[] = $this ->sql;
         $this ->u_sqls[] = $this ->sql;
         if ( $this ->u_conn == null) {
             $this ->connectDB( "master" );
         }
  
         $this ->urs = mysqli_query( $this ->u_conn, $sql , MYSQLI_USE_RESULT);
         $this ->update_num++;
  
         if (! $this ->urs) {
             return false;
         } else {
             return true;
         }
     }
}

至此,基本框架已经出来了,来看看调用方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?php
// 连接到第一组会话服务器
$db = &DB::init( $configs , 'session.0' );
//  执行一次查询
$db [ 'session' ][0]->query( 'SELECT ...' );
  
//  再次连接BLOG服务器
$db = &DB::init( $configs , 'blog.1' );
//  执行一次更新
$db [ 'blog' ][1]->update( 'UPDATE ...' );
  
//  再次调用会话更新
$db [ 'session' ][0]->update( 'INSERT ...' );
?>

转载于:https://my.oschina.net/tenking/blog/28574

多数据库支持的应用程序设计(来自深空老大)相关推荐

  1. 浅谈权限设计(来自深空老大)

    2019独角兽企业重金招聘Python工程师标准>>> By 深空, 2009-09-13 21:45:07 PHPChina的专家版在谈权限设计,苦于没有权限回帖,特发此博文谈谈简 ...

  2. 系出名门Android(9) - 数据库支持(SQLite), 内容提供器(ContentProvider)

    [索引页] [×××] 系出名门Android(9) - 数据库支持(SQLite), 内容提供器(ContentProvider) 作者:webabcd 介绍 在 Android 中使用 SQLit ...

  3. 简易文章PHP mysql代码,一个没有MYSQL数据库支持的简易留言本的_php

    由于国内mysql资源比较紧张,国外的不是太慢,就是不对我国用户开放.因此,在没有MYSQL的日子里,我们想做一些方便他人和完善自己站点的事情,那简直比登天还难,为了摆脱这种痛苦,niky哭思冥想,闭 ...

  4. tp3分布式session mysql_分布式数据库支持

    ThinkPHP内置了分布式数据库的支持,包括主从式数据库的读写分离,但是分布式数据库必须是相同的数据库类型. 配置`DB_DEPLOY_TYPE` 为1 可以采用分布式数据库支持.如果采用分布式数据 ...

  5. endnote初始化数据库支持_5 个免费的在线 SQL 数据库环境,比Navicat 香

    文章目录 SQL Fiddle DB Fiddle db<>fiddle SQL Online Oracle Live SQL 总结 今天给大家分享几个在线的免费 SQL 运行环境,也就是 ...

  6. 数据库(二)tab补全功能,使数据库支持简体中文,日志管理,备份脚本

    一.如何在MySQL数据库中使用tab键补全功能 1.修改主配置文件/etc/my.cnf vim /etc/my.cnf [mysql] #no-auto-rehash auto-rehash 2. ...

  7. 第十三章 数据库支持

    第十三章 数据库支持 本章讨论Python数据库API(一种连接到SQL数据库的标准化方式),并演示如何使用这个API来执行一些基本的SQL.最后,本章将讨论其他一些数据库技术. 关Python支持的 ...

  8. DreamFactory - 第3章生成数据库支持的API

    DreamFactory - 第3章生成数据库支持的API DreamFactory的功能十分强大,但是除了生成数据库支持的REST API之外,没有比这更受欢迎的功能了.通过采用这种自动化方法,开发 ...

  9. 数据库支持的数据类型

    数据库支持的数据类型 整型 # 建表 mysql>: create table tb1(x tinyint, y smallint, z int(6));# 插入数据 mysql>: in ...

最新文章

  1. linux各文件夹的作用域
  2. 不焦虑、不内卷能拿图灵奖吗?来自智源研究院的灵魂拷问
  3. ​DL_WITH_PY系统学习(第3章)
  4. 了解在HCI部署VDI的优势
  5. 攻击者怎样使用HTML和CSS隐藏“外部发件人”电子邮件警告
  6. c++修复工具_几款平价又好用的U盘修复工具分享
  7. Python二分查找算法
  8. Enjoy Android
  9. 运行报错provider = models.ForeignKey(Provider, on_delete=True) TypeError(‘on_delete must be callable.‘)
  10. 圆上的定理 —— 圆周角定理与相交弦定理
  11. CF1399E2 Weights Division (hard version)
  12. html添加田字,兆加页(是加三个田是什么字)
  13. 小程序的通知授权功能
  14. android 强制锁屏app,自制力app强制锁屏
  15. python通过正则匹配指定字符开头与结束提取中间内容
  16. 计算机文化考试论文,计算机文化基础论文
  17. mysql 三表关联查询
  18. Linux中 vi、删除和退出 简单操作
  19. python 统计哈姆雷特词汇频率_Python练习15:文本单词频率统计:哈姆雷特,练习题,英文版...
  20. 完全免费的文件恢复工具

热门文章

  1. Microsoft二任CEO业绩对比,说明什么?
  2. Python 网络爬虫的常用库汇总
  3. matlab无限表示,[求助] 关于matlab无限循环的问题
  4. java16下载_java lombok下载
  5. Nacos配置管理模型
  6. 查看网卡[网络接口]
  7. wait/notify的基本使用
  8. 完成AOP 顶层设计-CglibAopProxy
  9. Redis中的代理Sharding
  10. 关于Spring容器管理Bean的过程以及加载模式