mysql读写分离(PHP类)

本文涉及的产品
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS PostgreSQL,集群系列 2核4GB
简介: mysql读写分离(PHP类) 博客分类:   php mysql     自己实现了php的读写分离,并且不用修改程序 优点:实现了读写分离,不依赖服务器硬件配置,并且都是可以配置read服务器,无限扩展 缺点:错误转移不购明确,现只有3次尝试机会,失败了就会选择其他的服务器.

mysql读写分离(PHP类)

博客分类:
 

 

自己实现了php的读写分离,并且不用修改程序

优点:实现了读写分离,不依赖服务器硬件配置,并且都是可以配置read服务器,无限扩展

缺点:错误转移不购明确,现只有3次尝试机会,失败了就会选择其他的服务器.当服务器恢复时,需要手动去消除错误日志不人性化

修改于discux x 的mysql类

配置文件

"db"=>array(
        '1'=>array(
            'dbhost'=> '127.0.0.1',
            'dbuser' => 'root',
            'dbpw' => 'xxx',
            'dbcharset' => 'utf8',
            'pconnect' => '0',
            'dbname' => 'test',
            'tablepre' => 'w_',
        ),
        '2'=>array(
            'dbhost'=> '127.0.0.1',
            'dbuser' => 'root',
            'dbpw' => 'xxx',
            'dbcharset' => 'utf8',
            'pconnect' => '0',
            'dbname' => 'test2',
            'tablepre' => 'w_',
        ),
        
        '3'=>array(
            'dbhost'=> '127.0.0.1',
            'dbuser' => 'root',
            'dbpw' => 'xxx',
            'dbcharset' => 'utf8',
            'pconnect' => '0',
            'dbname' => 'test3',
            'tablepre' => 'w_',
        ),
        'writes'=>array('2','3'),
        'reads'=>array('2','1'),
        'broken'=>array(),
        'broken_file'=>str_replace('\\','/',dirname(__FILE__)) ."/____mysql_broken_file.php",
        //'broken_file'=>array(),
     )

类文件

<?php

/*
    [Discuz!] (C)2001-2009 Comsenz Inc.
    This is NOT a freeware, use is subject to license terms

    $Id: db_mysql.class.php 20294 2009-09-23 06:00:37Z zhaoxiongfei $
*/

if(!defined('IN_APP')) {
    exit('Access Denied');
}

class lib_db_mysql extends app_lib
{
    var $tablepre;
    var $version = '';
    var $querynum = 0;
    var $curlink;
    var $link = array();
    var $config = array();
    var $sqldebug = array();
    var $map = array();
    
    var $reads=array();//读服务器id
    var $writes=array();//写服务器id
    var $broken=array();//重试3次坏掉的服务器
    var $broken_file="";
    
    function init(){
        $this->set_config(config_item('db'));
    }

    function set_config($config) {
        $this->config = &$config;
        $this->tablepre = $config['1']['tablepre'];
        if(!empty($this->config['map'])) {
            $this->map = $this->config['map'];
        }
        
        /**
        * 读写分离
        */
        if(!empty($this->config['reads'])) {
            $this->reads=$this->config['reads'];
            unset($this->config['reads']);
        }
        
        if(!empty($this->config['writes'])) {
            $this->writes=$this->config['writes'];
            unset($this->config['writes']);
        }

        if(!empty($this->config['broken_file'])) {
            $this->broken_file=$this->config['broken_file'];
            unset($this->config['broken_file']);
        }else{
            $this->broken_file=str_replace('\\','/',dirname(__FILE__)) ."/____mysql_broken_file.php";
        }
        
        $this->broken=$this->get_broken($this->config['broken']);
        unset($this->config['broken']);

        
        //-读写分离
    }

    function connect($serverid = 1) {

        if(empty($this->config) || empty($this->config[$serverid])) {
            $this->set_broken($serverid);
            $this->halt('config_db_not_found');
        }

        $this->link[$serverid] = $this->_dbconnect(
            $this->config[$serverid]['dbhost'],
            $this->config[$serverid]['dbuser'],
            $this->config[$serverid]['dbpw'],
            $this->config[$serverid]['dbcharset'],
            $this->config[$serverid]['dbname'],
            $this->config[$serverid]['pconnect'],
            $serverid
            );
        $this->curlink = $this->link[$serverid];
    }

    function _dbconnect($dbhost, $dbuser, $dbpw, $dbcharset, $dbname, $pconnect,$serverid=0) {
        $link = null;
        $func = empty($pconnect) ? 'mysql_connect' : 'mysql_pconnect';
        if(!$link = @$func($dbhost, $dbuser, $dbpw, 1)) {
            $this->set_broken($serverid);
            $this->halt('notconnect');
        } else {
            $this->curlink = $link;
            if($this->version() > '4.1') {
                $dbcharset = $dbcharset ? $dbcharset : $this->config[1]['dbcharset'];
                $serverset = $dbcharset ? 'character_set_connection='.$dbcharset.', character_set_results='.$dbcharset.', character_set_client=binary' : '';
                $serverset .= $this->version() > '5.0.1' ? ((empty($serverset) ? '' : ',').'sql_mode=\'\'') : '';
                $serverset && mysql_query("SET $serverset", $link);
            }
            $dbname && @mysql_select_db($dbname, $link);
        }
        return $link;
    }

    function table($tablename) {
        if(!empty($this->map) && !empty($this->map[$tablename])) {
            $id = $this->map[$tablename];
            if(!$this->link[$id]) {
                $this->connect($id);
            }
            $this->curlink = $this->link[$id];
        } else {
            $this->curlink = $this->link[1];
        }
        return $this->tablepre.$tablename;
    }

    function select_db($dbname) {
        return mysql_select_db($dbname, $this->curlink);
    }

    function fetch_array($query, $result_type = MYSQL_ASSOC) {
        return mysql_fetch_array($query, $result_type);
    }

    function fetch_first($sql) {
        return $this->fetch_array($this->query($sql));
    }

    function result_first($sql) {
        return $this->result($this->query($sql), 0);
    }

    /**
    * 读写分离,并从池中选中随机选中数据库
    * 如果没有read连接将使用write代替
    * 
    * @param string $sql
    */
    function switch_server($sql,$default=1){
        $sql=ltrim($sql);
        if(preg_match('/^select/i',$sql)){
            $type='reads';
        }else{
            $type='writes';
        }

        $servers=array_diff($this->$type,$this->filter_broken($this->broken)); 
        if(!$servers&&$type=='reads'){
            $type='writes';
            $servers=array_diff($this->$type,$this->filter_broken($this->broken)); 
        }
        
        $t=count($servers);
        if($t>0){
            //有合理的服务
            /**
            * 根据ip的hash随机抽服务器运行,
            */
            $servers=array_values($servers);
            $onlineip = '';
            if(getenv('HTTP_CLIENT_IP') && strcasecmp(getenv('HTTP_CLIENT_IP'), 'unknown')) {
                $onlineip = getenv('HTTP_CLIENT_IP');
            } elseif(getenv('HTTP_X_FORWARDED_FOR') && strcasecmp(getenv('HTTP_X_FORWARDED_FOR'), 'unknown')) {
                $onlineip = getenv('HTTP_X_FORWARDED_FOR');
            } elseif(getenv('REMOTE_ADDR') && strcasecmp(getenv('REMOTE_ADDR'), 'unknown')) {
                $onlineip = getenv('REMOTE_ADDR');
            } elseif(isset($_SERVER['REMOTE_ADDR']) && $_SERVER['REMOTE_ADDR'] && strcasecmp($_SERVER['REMOTE_ADDR'], 'unknown')) {
                $onlineip = $_SERVER['REMOTE_ADDR'];
            }
            
            !$onlineip&&$onlineip=rand(100);

            $i=abs(crc32($onlineip))%$t;

            return $servers[$i];
        }
        return $default;
    }
    
    
    function set_broken($server_id){
        $this->broken[$server_id]++;
        if($this->broken_file){
            $str=var_export($this->broken,true);
            $c="<?php 
                \$broken=$str;
            ?>";
            return file_put_contents($this->broken_file,$c);
        }
    }
    
    function filter_broken($broken){
        $error_try=3;
        foreach($broken as $id=>$num){
            if($num<$error_try){
                unset($broken[$id]);
            }
        }
        return array_keys($broken);
    }
    
    function get_broken($realbroken){
        $broken=array();
        $error_try=3;
        if($this->broken_file&&is_file($this->broken_file)){
            @include($this->broken_file);
        }
        settype($realbroken,'array');
        foreach($realbroken as $id){
            $broken[$id]=$error_try;
        }
        return $broken;
    }
    
    /**
    * 读写分离
    * 
    * @param mixed $sql
    * @param mixed $type
    */
    
    function query($sql, $type = '') {

        if(defined('DISCUZ_DEBUG') && DISCUZ_DEBUG) {
            $starttime = dmicrotime();
        }
        
        //读写分离
        $server_id=$this->switch_server($sql,1);

        if($this->link[$server_id]){
            $this->curlink=$this->link[$server_id];
        }else{
            $this->connect($server_id);
        }
        //-读写分离
        
        
        
        $func = $type == 'UNBUFFERED' && @function_exists('mysql_unbuffered_query') ?
        'mysql_unbuffered_query' : 'mysql_query';
        if(!($query = $func($sql, $this->curlink))) {
            if(in_array($this->errno(), array(2006, 2013)) && substr($type, 0, 5) != 'RETRY') {
                $this->connect($server_id);
                return $this->query($sql, 'RETRY'.$type);
            }
            if($type != 'SILENT' && substr($type, 5) != 'SILENT') {
                $this->halt('query_error', $sql);
            }
        }

        if(defined('DISCUZ_DEBUG') && DISCUZ_DEBUG) {
            $this->sqldebug[] = array($sql, number_format((dmicrotime() - $starttime), 6), debug_backtrace());
        }

        $this->querynum++;
        return $query;
    }

    function affected_rows() {
        return mysql_affected_rows($this->curlink);
    }

    function error() {
        return (($this->curlink) ? mysql_error($this->curlink) : mysql_error());
    }

    function errno() {
        return intval(($this->curlink) ? mysql_errno($this->curlink) : mysql_errno());
    }

    function result($query, $row = 0) {
        $query = @mysql_result($query, $row);
        return $query;
    }

    function num_rows($query) {
        $query = mysql_num_rows($query);
        return $query;
    }

    function num_fields($query) {
        return mysql_num_fields($query);
    }

    function free_result($query) {
        return mysql_free_result($query);
    }

    function insert_id() {
        return ($id = mysql_insert_id($this->curlink)) >= 0 ? $id : $this->result($this->query("SELECT last_insert_id()"), 0);
    }

    function fetch_row($query) {
        $query = mysql_fetch_row($query);
        return $query;
    }

    function fetch_fields($query) {
        return mysql_fetch_field($query);
    }

    function version() {
        if(empty($this->version)) {
            $this->version = mysql_get_server_info($this->curlink);
        }
        return $this->version;
    }

    function close() {
        return mysql_close($this->curlink);
    }

    function halt($message = '', $sql = '') {
        global $_G;
        $dberror = $this->error();
        $dberrno = $this->errno();
        $phperror = '<table style="font-size:11px" cellpadding="0"><tr><td width="270">File</td><td width="80">Line</td><td>Function</td></tr>';
        foreach (debug_backtrace() as $error) {
            $error['file'] = str_replace(DISCUZ_ROOT, '', $error['file']);
            $error['class'] = isset($error['class']) ? $error['class'] : '';
            $error['type'] = isset($error['type']) ? $error['type'] : '';
            $error['function'] = isset($error['function']) ? $error['function'] : '';
            $phperror .= "<tr><td>$error[file]</td><td>$error[line]</td><td>$error[class]$error[type]$error[function]()</td></tr>";
        }
        $phperror .= '</table>';
        $helplink = "http://faq.comsenz.com/?type=mysql&dberrno=".rawurlencode($dberrno)."&dberror=".rawurlencode($dberror);
        @header('Content-Type: text/html; charset='.$_G['config']['output']['charset']);
        echo '<div style="position:absolute;font-size:11px;font-family:verdana,arial;background:#EBEBEB;padding:0.5em;line-height:1.5em">';

        echo "<b>PHP Backtrace</b><br />$sql error<br /> $dberror</div>";
        exit();
    }
    
    
    function delete($table, $condition, $limit = 0, $unbuffered = true) {
        if(empty($condition)) {
            $where = '1';
        } elseif(is_array($condition)) {
            $where = $this->implode_field_value($condition, ' AND ');
        } else {
            $where = $condition;
        }
        $sql = "DELETE FROM ".$this->table($table)." WHERE $where ".($limit ? "LIMIT $limit" : '');
        return $this->query($sql, ($unbuffered ? 'UNBUFFERED' : ''));
    }

    function insert($table, $data, $return_insert_id = false, $replace = false, $silent = false) {

        $sql = $this->implode_field_value($data);

        $cmd = $replace ? 'REPLACE INTO' : 'INSERT INTO';

        $table = $this->table($table);
        $silent = $silent ? 'SILENT' : '';

        $return = $this->query("$cmd $table SET $sql", $silent);

        return $return_insert_id ? $this->insert_id() : $return;

    }

    function update($table, $data, $condition, $unbuffered = false, $low_priority = false) {
        $sql = $this->implode_field_value($data);
        $cmd = "UPDATE ".($low_priority ? 'LOW_PRIORITY' : '');
        $table = $this->table($table);
        $where = '';
        if(empty($condition)) {
            $where = '1';
        } elseif(is_array($condition)) {
            $where = $this->implode_field_value($condition, ' AND ');
        } else {
            $where = $condition;
        }
        $res = $this->query("$cmd $table SET $sql WHERE $where", $unbuffered ? 'UNBUFFERED' : '');
        return $res;
    }

    function implode_field_value($array, $glue = ',') {
        $sql = $comma = '';
        foreach ($array as $k => $v) {
            $sql .= $comma."`$k`='$v'";
            $comma = $glue;
        }
        return $sql;
    }

}

相关实践学习
如何在云端创建MySQL数据库
开始实验后,系统会自动创建一台自建MySQL的 源数据库 ECS 实例和一台 目标数据库 RDS。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
目录
相关文章
|
1月前
|
负载均衡 监控 关系型数据库
MySQL 官宣:支持读写分离了!!
【10月更文挑战第8天】MySQL的读写分离功能显著提升了数据库性能、可用性和可靠性。通过将读写操作分配至不同服务器,有效减轻单个服务器负载,提高响应速度与吞吐量,并增强系统稳定性。此外,它还支持便捷的扩展方式,可通过增加只读服务器提升读操作性能。实现读写分离的方法包括软件层面(如使用数据库中间件)和硬件层面(使用独立服务器)。使用时需注意数据一致性、负载均衡及监控管理等问题。
116 0
|
8天前
|
关系型数据库 MySQL PHP
PHP与MySQL动态网站开发实践指南####
深入探索PHP与MySQL结合的魅力,本文旨在通过一系列实战案例,揭示如何高效构建动态交互式网站。从环境搭建到代码实现,全方位解析两者协同工作的原理与技巧,为开发者提供一条清晰的学习路径。 ####
|
13天前
|
SQL 关系型数据库 MySQL
12 PHP配置数据库MySQL
路老师分享了PHP操作MySQL数据库的方法,包括安装并连接MySQL服务器、选择数据库、执行SQL语句(如插入、更新、删除和查询),以及将结果集返回到数组。通过具体示例代码,详细介绍了每一步的操作流程,帮助读者快速入门PHP与MySQL的交互。
28 1
|
18天前
|
存储 关系型数据库 MySQL
PHP与MySQL动态网站开发深度解析####
本文作为技术性文章,深入探讨了PHP与MySQL结合在动态网站开发中的应用实践,从环境搭建到具体案例实现,旨在为开发者提供一套详尽的实战指南。不同于常规摘要仅概述内容,本文将以“手把手”的教学方式,引导读者逐步构建一个功能完备的动态网站,涵盖前端用户界面设计、后端逻辑处理及数据库高效管理等关键环节,确保读者能够全面掌握PHP与MySQL在动态网站开发中的精髓。 ####
|
19天前
|
关系型数据库 MySQL PHP
PHP与MySQL动态网站开发实战指南####
本文深入探讨了PHP与MySQL在动态网站开发中的应用实践,通过具体案例解析如何高效结合这两大技术构建数据驱动的Web应用。文章将涵盖环境搭建、基础语法回顾、数据库设计与操作、用户注册与登录系统实现等关键步骤,旨在为开发者提供一个从零到一的项目实战路径,展示PHP与MySQL协同工作的强大能力。 ####
|
1月前
|
SQL 关系型数据库 MySQL
PHP与MySQL协同工作的艺术:开发高效动态网站
在这个后端技术迅速迭代的时代,PHP和MySQL的组合仍然是创建动态网站和应用的主流选择之一。本文将带领读者深入理解PHP后端逻辑与MySQL数据库之间的协同工作方式,包括数据的检索、插入、更新和删除操作。文章将通过一系列实用的示例和最佳实践,揭示如何充分利用这两种技术的优势,构建高效、安全且易于维护的动态网站。
|
1月前
|
设计模式 SQL 安全
PHP中的设计模式:单例模式的深入探索与实践在PHP开发领域,设计模式是解决常见问题的高效方案集合。它们不是具体的代码,而是一种编码和设计经验的总结。单例模式作为设计模式中的一种,确保了一个类仅有一个实例,并提供一个全局访问点。本文将深入探讨单例模式的基本概念、实现方式及其在PHP中的应用。
单例模式在PHP中的应用广泛,尤其在处理数据库连接、日志记录等场景时,能显著提高资源利用率和执行效率。本文从单例模式的定义出发,详细解释了其在PHP中的不同实现方法,并探讨了使用单例模式的优势与注意事项。通过对示例代码的分析,读者将能够理解如何在PHP项目中有效应用单例模式。
|
6月前
|
关系型数据库 MySQL PHP
【PHP 开发专栏】PHP 连接 MySQL 数据库的方法
【4月更文挑战第30天】本文介绍了 PHP 连接 MySQL 的两种主要方法:mysqli 和 PDO 扩展,包括连接、查询和处理结果的基本步骤。还讨论了连接参数设置、常见问题及解决方法,如连接失败、权限和字符集问题。此外,提到了高级技巧如使用连接池和缓存连接信息以优化性能。最后,通过实际案例分析了在用户登录系统和数据管理中的应用。
501 1
|
存储 SQL 前端开发
【PHP】一文详解如何连接Mysql数据库(附源码)
本文主要讲解PHP如何连接数据库并且根据前端的form表单提交的数据返回到数据库最后查询出来展现
354 0
【PHP】一文详解如何连接Mysql数据库(附源码)
|
关系型数据库 MySQL PHP
PHP连接MySQL数据库
PHP连接MySQL数据库
下一篇
无影云桌面