IT虾米网

一个 MySQL 分库分表php类详解

itxm 2018年06月24日 数据库 563 0

当一个表数据记录过大时就会出现性能瓶颈,而一般对应的解决办法是要么做分区表,要么分表,分区表就不说了,分表又分为垂直分割和水平分割,具体区 别请自行搜索。一般而言,分库分表属于水平分割,按照一定的规则将数据插入到不同的表中去。而分库则可以很方便的转移数据库的压力,比如将一个很大库的分 别放在不同的服务器上。

下面是我写的一个分库分表的实现:

    <?php   
    /**  
     * User: guoyu  
     * Date: 14-8-12  
     * Time: 下午3:16  
     */   
        
    namespace App\Model\Database;   
        
    class Config   
    {   
        public $dsn;   
        public $user;   
        public $password;   
        /**  
         * @var string 分库分表后得到的数据库名  
         */   
        public $dbname;   
        /**  
         * @var string 分库分表后得到的表名  
         */   
        public $table;   
        
        /**  
         * @var array MySQL 配置数组  
         */   
        private static $config;   
        
        /**  
         * @var string 配置文件路径  
         */   
        private static $configFile = 'mysql.php';   
        
        public function __construct($dbname, $table, $id = 0)   
        {   
            if (is_null(static::$config)) {   
                $config = include(static::$configFile);   
                static::$config = $config;   
            }   
        
            $config = static::$config;   
            if (isset($config['shared']) && isset($config['shared'][$dbname])) {   
                $dbconfig = $config['shared'][$dbname];   
                $id = is_numeric($id) ? (int)$id : crc32($id);   
                $database_id = ($id / $dbconfig['database_split'][0]) % $dbconfig['database_split'][1];   
                $table_id = ($id / $dbconfig['table_split'][0]) % $dbconfig['table_split'][1];   
        
                foreach ($dbconfig['host'] as $key => $conf) {   
                    list($from, $to) = explode('-', $key);   
                    if ($from <= $database_id && $database_id <= $to) {   
                        $the_config = $conf;   
                    }   
                }   
        
                $this->dbname = $dbname . '_' . $database_id;   
                $this->table = $table . '_' . $table_id;   
            } else {   
                $this->dbname = $dbname;   
                $this->table = $table;   
                $the_config = $config['db'][$dbname];   
            }   
            $c = $the_config;   
            if (isset($c['unix_socket']) && $c['unix_socket']) {   
                $this->dsn = sprintf('mysql:dbname=%s;unix_socket=%s', $this->dbname, $c['unix_socket']);   
            } else {   
                $this->dsn = sprintf('mysql:dbname=%s;host=%s;port=%s', $this->dbname, $c['host'], $c['port']);   
            }   
            $this->user = $c['user'];   
            $this->password = $c['password'];   
        }   
        
    }   
 
 
Config 类就做一个事情,根据配置文件,去拿到对应的库和表的链接配置,然后客户可以根据 dsn 去链接对应的数据库。对应的配置文件如下: 
 
[php] view plaincopyprint?在CODE上查看代码片派生到我的代码片 
 
    <?php   
    /**  
     * User: guoyu  
     * Date: 14-8-6  
     * Time: 上午11:19  
     */   
        
    $default = array(   
        'unix_socket' => null,   
        'host' => 'localhost',   
        'port' => '3306',   
        'user' => 'root',   
        'password' => '',   
    );   
        
    $config = array(   
        // 不进行分库分表的数据库   
        'db' => array(   
            'my_site' => $default,   
        ),   
        // 分库分表   
        'shared' => array(   
            'user' => array(   
                'host' => array(   
                    /**  
                     * 编号为 0 到 10 的库使用的链接配置  
                     */   
                    '0-10' => $default,   
                    /**  
                     * 编号为 11 到 28 的库使用的链接配置  
                     */   
                    '11-28' => $default,   
                    /**  
                     * 编号为 29 到 99 的库使用的链接配置  
                     */   
                    '29-99' => $default,   
        
                ),   
        
                // 分库分表规则   
                /**  
                 * 下面的配置对应百库百表  
                 * 如果根据 uid 进行分表,假设 uid 为 543234678,对应的库表为:  
                 *  (543234678 / 1) % 100 = 78 为编号为 78 的库  
                 *  (543234678 / 100) % 100 = 46 为编号为 46 的表  
                 */   
                'database_split' => array(1, 100),   
                'table_split' => array(100, 100),   
            ),   
        ),   
    );   
        
        
    return $config;   
 
 
给出一个使用这个分库分表的例子: 
 
[php] view plaincopyprint?在CODE上查看代码片派生到我的代码片 
 
    <?php   
    /**  
     * User: guoyu  
     * Date: 14-8-6  
     * Time: 上午10:23  
     */   
        
    namespace App\Model;   
        
    use App\Model\Database\Config;   
    use \PDO;   
        
    abstract class Model   
    {   
        /**  
         * @var Config  
         */   
        public $config;   
        
        /**  
         * @var PDO  
         */   
        public $connection;   
        
        protected $dbnamePrefix;   
        protected $tablePrefix;   
        
        /**  
         * @var string 分库分表后对应的表  
         */   
        protected $table;   
        
        public function __construct($id)   
        {   
            $this->config = new Config($this->dbnamePrefix, $this->tablePrefix, $id);   
            $this->connection = new Pdo($this->config->dsn, $this->config->user, $this->config->password);   
            $this->table = $this->config->table;   
        }   
        
        public function update(array $data, array $where = array())   
        {   
        
        }   
        
        public function select(array $where)   
        {   
        
        }   
        
        public function insert(array $data)   
        {   
        
        }   
        
        public function query($sql)   
        {   
            return $this->connection->query($sql);   
        }   
    }  

下面这个例子展示了如何使用上述的 Model 类:
    <?php   
    /**  
     * User: guoyu  
     * Date: 14-8-12  
     * Time: 下午4:06  
     */   
        
    require 'Config.php';   
    require 'Model.php';   
        
    use App\Model\Model;   
        
    class User extends Model   
    {   
        protected $dbnamePrefix = 'user';   
        protected $tablePrefix = 'userinfo';   
    }   
        
    $user = new User(4455345345);   
        
    print_r($user);  

来自:http://blog.csdn.net/phpfenghuo/article/details/45342311
发布评论

分享到:

IT虾米网

微信公众号号:IT虾米 (左侧二维码扫一扫)欢迎添加!

每天自动备份mysql脚本详解
你是第一个吃螃蟹的人
发表评论

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。