PHP实现同步2个服务器MYSQL表及表结构,表同步,表结构同步

1.第一步先同步表

查询出要当前数据库对比源数据库需要删除的表和需要新建的表,同步表数据
重点语句:

  • SHOW TABLES (显示当前数据库中所有表的名称)
  • DROP TABLE {表名} (删除当前数据库中该表)
  • SHOW CREATE TABLE {表名} (获取创建该表的语句)

2.第二步再对比表结构->同步表结构

查询出两个数据库中表所有的字段,对比不同的表结构
重点语句:

  • SELECT * FROM INFORMATION_SCHEMA.COLUMNS WHERE table_name IN({表名数据}) AND table_schema = '{数据库名}' (获取当前库所有表的表结构)
  • SELECT COLUMN_NAME from INFORMATION_SCHEMA.COLUMNS where ORDINAL_POSITION = {列标识号} and table_schema = '{数据库名}' and table_name = '{表名}' (获取当前库该表的列标识号对应的字段名称)

3.第三步直接上代码

<?php
function dd($arr){
    echo "<pre>";
    var_dump($arr);
    echo "</pre>";
    die();
}

class MysqlSync{

    /**
     * 执行状态记录
     * @var array
     */
    private $stat = array();
    /**
     * 默认值需要加上引号的类型的索引
     * @var array
     */
    private $convert_map = array('varchar', 'char', 'tinytext', 'mediumtext', 'text', 'longtext', 'enum');

    /**
     * 数据库结构同步
     * @param $selfConf
     * @param $sourceConf
     * @return array
     */
    function sync($selfConf, $sourceConf){
        $self = mysqli_connect($selfConf['host'], $selfConf['user'], $selfConf['pwd'], $selfConf['db']);
        $source = mysqli_connect($sourceConf['host'], $sourceConf['user'], $sourceConf['pwd'], $sourceConf['db']);
        //删表 ,建表
        $selfData = $this->getTable($self);     //获取本身,和对比源的结构
        $sourceData = $this->getTable($source);
        $removeList = array_diff($selfData, $sourceData);       //如果自身有,源没有,就删除
        $createList = array_diff($sourceData, $selfData);       //如果源有,自身没有,就新增
        if(!empty($removeList)){        //执行删除操作
            $remove_tab = '';
            foreach($removeList as $val){
                $remove_tab .= "`{$val}`,";
            }
            $remove_tab = trim($remove_tab, ',');
            $remove_sql = "DROP TABLE {$remove_tab}";
            if($self->query($remove_sql)){
                $this->stat['success'][] = $remove_sql;
            }else{
                $this->stat['error'][] = $remove_sql;
            }
        }

        if(!empty($createList)){        //执行新增操作
            foreach($createList as $val){
                $create_sql = "SHOW CREATE TABLE `{$val}`";
                if($sql = $source->query($create_sql)->fetch_row()){
                    if($self->query($sql[1])){
                        $this->stat['success'][] = $sql[1];
                    }else{
                        $this->stat['error'][] = $sql[1];
                    }
                }
            }
        }

        //表结构
        $selfStructure = $this->getStructure($self,$selfConf['db']);
        $sourceStructure = $this->getStructure($source,$sourceConf['db']);
        foreach($sourceStructure as $pKey => $item){     //对比表的字段是否相同
            $val = $selfStructure[$pKey];
            if ($val){
                //dd($item);
                $removeColumn = array_diff_key($val, $item);
                $addColumn = array_diff_key($item, $val);
                if(!empty($removeColumn)){
                    foreach($removeColumn as $removeVal){
                        $removeColumnSql = "ALTER TABLE `{$pKey}` DROP COLUMN `{$removeVal['COLUMN_NAME']}`";
                        if($self->query($removeColumnSql)){
                            $this->stat['success'][] = $removeColumnSql;
                        }else{
                            $this->stat['error'][] = $removeColumnSql;
                        }
                    }
                }
                //dd($addColumn);
                if(!empty($addColumn)){
                    foreach($addColumn as $addVal){
                        $addInfo = "`{$addVal['COLUMN_NAME']}` {$addVal['COLUMN_TYPE']}";
                        //字符编码
                        if ($addVal['CHARACTER_SET_NAME']){
                            $addInfo .= " CHARACTER SET {$addVal['CHARACTER_SET_NAME']}";
                        }
                        //字符编码
                        if ($addVal['COLLATION_NAME']){
                            $addInfo .= " COLLATE {$addVal['COLLATION_NAME']}";
                        }
                        //是否为null
                        if ($addVal['IS_NULLABLE'] == 'NO'){
                            $addInfo .= " NOT NULL";
                        }
                        //默认值
                        if ($addVal['COLUMN_DEFAULT']!==null){
                            if(in_array($addVal['DATA_TYPE'], $this->convert_map)){
                                $addInfo .= " DEFAULT '{$addVal['COLUMN_DEFAULT']}'";
                            }else{
                                $addInfo .= " DEFAULT {$addVal['COLUMN_DEFAULT']}";
                            }
                        }

                        //EXTRA
                        if ($addVal['EXTRA']){
                            $addInfo .= " {$addVal['EXTRA']}";
                        }
                        //备注信息
                        if ($addVal['COLUMN_COMMENT']){
                            $addInfo .= " COMMENT '{$addVal['COLUMN_COMMENT']}'";
                        }
                        if($addVal['ORDINAL_POSITION'] == 1)
                        {
                            $addInfo .= " first";
                        }
                        else
                        {
                            $last_pos = $addVal['ORDINAL_POSITION'] - 1;
                            $last_col = $this->getAlterAfter($source,$sourceConf['db'],$addVal['TABLE_NAME'],$last_pos);
                            $addInfo .= " AFTER `{$last_col[0]['COLUMN_NAME']}`";
                        }
                        $addSql = "ALTER TABLE `{$pKey}` ADD COLUMN {$addInfo}";
                        if($self->query($addSql)){
                            $this->stat['success'][] = $addSql;
                        }else{
                            $this->stat['error'][] = $addSql;
                        }
                    }
                }
            }

        }
        return $this->stat;
    }

    /**
     * 获取表结构
     * @param $resource
     * @param $db
     * @return array
     */
    function getStructure($resource, $db){
        $table_str = '';
        $info = array();
        $sql_table = 'SHOW TABLES';
        $res_table = $resource->query($sql_table);
        while($row_table = $res_table->fetch_assoc()){
            $table_str .= "'" . current($row_table) . "',";
        }
        $table_str = trim($table_str, ',');
        $column_sql = "SELECT * FROM INFORMATION_SCHEMA.COLUMNS WHERE table_name IN({$table_str}) AND table_schema = '{$db}'";
        $column_res = $resource->query($column_sql);
        if($column_res) {
            while ($row_column = $column_res->fetch_assoc()) {
                $info[] = $row_column;
            }
            return $this->gen($info);
        }else{
            return array();
        }
    }

    /**
     * 获取字段排序
     * @param $resource
     * @param $db
     * @param $table
     * @param $lastPos
     * @return array
     */
    function getAlterAfter($resource,$db,$table,$lastPos){
        $info = [];
        $column_sql = "SELECT COLUMN_NAME from INFORMATION_SCHEMA.COLUMNS where ORDINAL_POSITION = {$lastPos} and table_schema = '{$db}' and table_name = '{$table}'";
        $column_res = $resource->query($column_sql);
        if($column_res) {
            while ($row_column = $column_res->fetch_assoc()) {
                $info[] = $row_column;
            }
        }
        return $info;
    }
    /**
     * 获取表列表
     * @param $resource
     * @param $db
     * @return array
     */
    function getTable($resource){
        $table_arr = [];
        $sql_table = 'SHOW TABLES';
        $res_table = $resource->query($sql_table);
        while($row_table = $res_table->fetch_assoc()){
            $table_arr []= current($row_table);
        }
        return $table_arr;
    }

    /**
     * 数据排序处理
     * @param $array
     * @return array
     */
    function gen($array){
        $data = array();
        foreach($array as $key => $item){
            if(!array_key_exists($item['TABLE_NAME'], $data)) {
                foreach ($array as $value) {
                    if ($value['TABLE_NAME'] == $item['TABLE_NAME']) {
                        $data[$item['TABLE_NAME']][$value['COLUMN_NAME']] = $value;
                    }
                }
            }
        }
        return $data;
    }

}

$sync = new MysqlSync();
$selfConf = array(      //待同步数据库
    'host'  => 'localhost',
    'user'  => 'root',
    'pwd'   => 'root',
    'db'    => 'yinghuo'
);
$sourceConf = array(        //同步来源数据库
    'host'  => 'localhost',
    'user'  => 'root',
    'pwd'   => 'root',
    'db'    => 'tp'
);
$res = $sync->sync($selfConf, $sourceConf);
dd($res);

4.有优化的地方请及时评论,我要更新

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,793评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,567评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,342评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,825评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,814评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,680评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,033评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,687评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,175评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,668评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,775评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,419评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,020评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,978评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,206评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,092评论 2 351
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,510评论 2 343