当前位置: 首页 > 图文教程 > 网络编程 > PHP > php多数据库支持的应用程序设计

PHP
php 多线程上下文中安全写文件实现代码
PHP类的使用 实例代码讲解
用php实现让页面只能被百度gogole蜘蛛访问的方法
php 学习笔记
PHP编程过程中需要了解的this,self,parent的区别
php 操作excel文件的方法小结
使用PHP获取网络文件的实现代码
PHP 巧用数组降低程序的时间复杂度
php下将XML转换为数组
php 文件上传代码(限制jpg文件)
php 无极分类(递归)实现代码
PHP 采集获取指定网址的内容
PHP 将图片按创建时间进行分类存储的实现代码
PHP 存储文本换行实现方法
PHP 批量更新网页内容实现代码
用PHP查询搜索引擎排名位置的代码
用php实现的获取网页中的图片并保存到本地的代码
php实现首页链接查询 友情链接检查的代码
处理php自动反斜杠的函数代码
php实现的遍历文件夹下所有文件,编辑删除

PHP 中的 php多数据库支持的应用程序设计


出处:互联网   整理: 软晨网(RuanChen.com)   发布: 2009-09-13   浏览: 58 ::
收藏到网摘: n/a

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

<?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的主从服务器,所以可以使用随机数来指定到某一台服务器。以下是一个简单的随机数实现:
复制代码 代码如下:

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;
}
}
}

  至此,基本框架已经出来了,来看看调用方法: <?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 ...');
?>