mysql 表结构差异对比小工具

本文介绍了一款用于比较两个数据库表结构差异的小工具。该工具能够连接数据库并获取表的创建语句,通过文本高亮显示差异部分,方便快速定位表结构的不同之处。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

项目场景:

在进行慢sql评审时,发现测试环境增加了索引生产并没有。然后有些表字段长度也不一样,坑大发了。决定写一个小工具对比一下测试跟生产表结构差异,大致思路连接数据库获取建表语句进行对比,忽略主键自增id。因为测试跟生产主键id自增会有不同,如果建表语句不一致,则需要比对文本高亮显示。在网上copy了一个别人写的高亮算法,生成了一个html预览。直接上代码


package com.xuyw.test.export;

import com.alibaba.druid.pool.DruidDataSource;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.io.FileUtils;
import org.springframework.jdbc.core.JdbcTemplate;

import java.io.File;
import java.io.IOException;
import java.util.*;


/**
 * @author one.xu
 * @version v1.0
 * @description
 * @date 2022/1/5 17:59
 */
public class DbComparedTest {
    private static JdbcTemplate db1;
    private static JdbcTemplate db2;

    static {
        db1 = new JdbcTemplate();
        DruidDataSource dataSource = new DruidDataSource();
        dataSource.setUrl("");
        dataSource.setUsername("");
        dataSource.setPassword("");
        db1.setDataSource(dataSource);


        db2 = new JdbcTemplate();
        DruidDataSource dataSource2 = new DruidDataSource();
        dataSource2.setUrl("");
        dataSource2.setUsername("");
        dataSource2.setPassword("");
        db2.setDataSource(dataSource2);
    }
    //移除AUTO_INCREMENT
    private static String handTable(String table) {
        return table.replaceAll("AUTO_INCREMENT=\\d+", "").trim();

    }
    //文本对比,高亮显示
    public static String getcompareStr(String char1, String char2) {
        String bcolor = "<span style='background-color:yellow;color:red;'>";
        String ecolor = "</span>";
        StringBuffer sb = new StringBuffer();
        char[] a = new char[char1.length()];
        for (int i = 0; i < char1.length(); i++) {
            a[i] = char1.charAt(i);
        }
        char[] b = new char[char2.length()];
        for (int i = 0; i < char2.length(); i++) {
            b[i] = char2.charAt(i);
        }
        // 不同字符集合
        Map<Object, Object> map1 = new HashMap<>();
        // 包含字符集合
        Map<Object, Object> map2 = new HashMap<>();
        for (int i = 0; i < a.length; i++) {
            if (i == a.length - 1) {
                if (i > 1) {
                    if (String.valueOf(b).contains(String.valueOf(a[i - 1]) + String.valueOf(a[i]))) {
                        map2.put(i - 1, a[i - 1]);
                        map2.put(i, a[i]);
                    } else {
                        map1.put(i, a[i]);
                    }
                } else {
                    map2.put(i, a[i]);
                }
            } else {
                if (String.valueOf(b).contains(String.valueOf(a[i]) + String.valueOf(a[i + 1]))) {
                    if (i > 1) {
                        if (String.valueOf(b).contains(String.valueOf(a[i - 1]) + String.valueOf(a[i]))) {
                            map2.put(i - 1, a[i - 1]);
                            map2.put(i, a[i]);
                        }
                    } else {
                        map2.put(i, a[i]);
                    }
                } else {
                    if (i > 0) {
                        if (String.valueOf(b).contains(String.valueOf(a[i - 1]) + String.valueOf(a[i]))) {
                            map2.put(i - 1, a[i - 1]);
                            map2.put(i, a[i]);
                        } else {
                            map1.put(i, a[i]);
                        }
                    } else {
                        map1.put(i, a[i]);
                    }
                }
            }
        }
        for (int i = 0; i < a.length; i++) {
            if (map1.get(i) != null) {
                sb.append(bcolor).append(map1.get(i)).append(ecolor);
            } else if (map2.get(i) != null) {
                sb.append(map2.get(i));
            }
        }
        return sb.toString();
    }

    public static void main(String[] args) throws IOException {
	    //需要比对的数据库名,多个逗号连接
        String dbs = "testDb1,testDb1";
        String tableSql = "select table_name,table_comment FROM information_schema.tables WHERE table_schema=?";
        //忽略比对的表名,多个逗号连接  支持正则
		String ignoreTable = "|(msg_log_\\w+)|(hand_log_\\w+)";
        String tableCreateSql = "show create table ";
        List<Map<String, Object>> tableDiffList = new ArrayList<>();
        Map<String, Object> diffMap;
        Map<String, Integer> dbTableCountMap = new HashMap<>();
        int dbTableCount = 0;
        for (String db : dbs.split(",")) {
            dbTableCount = 0;
            List<Map<String, Object>> tables = db1.queryForList(tableSql, db);
            for (int j = 0; j < tables.size(); j++) {
                String table = tables.get(j).get("table_name").toString();
                if (table.matches(ignoreTable)) {
                    continue;
                }
                diffMap = new HashMap<>();
                Map<String, Object> sourceTableMap = db1.queryForMap(tableCreateSql + db + "." + table);
                String sourceTable = handTable(MapUtils.getString(sourceTableMap, "Create Table"));
                diffMap.put("dbName", db);
                diffMap.put("sourceTable", sourceTable);
                Map<String, Object> targetTableMap;
                try {
                    targetTableMap = db2.queryForMap(tableCreateSql + db + "." + table);
                } catch (Exception e) {
                    dbTableCount = dbTableCount + 1;
                    diffMap.put("targetTable", "不存在");
                    tableDiffList.add(diffMap);
                    continue;
                }
                String targetTable = handTable(MapUtils.getString(targetTableMap, "Create Table"));
                if (sourceTable.equals(targetTable)) {
                    continue;
                }
                diffMap.put("targetTable", getcompareStr(targetTable, sourceTable));
                diffMap.put("sourceTable", getcompareStr(sourceTable, targetTable));
                tableDiffList.add(diffMap);
                dbTableCount = dbTableCount + 1;

            }
            dbTableCountMap.put(db, dbTableCount);
        }
        StringJoiner html = new StringJoiner("\n");
        html.add("<table style=\"font-size:12px;color:#333333;width:100%;border-width: 1px;border-color: #729ea5;border-collapse: collapse;\" border=\"1\">\n" +
                "<tr><th >数据库名</th><th>源表</th><th>对比表</th></tr>");

        for (Map<String, Object> m : tableDiffList) {
            String dbName=m.get("dbName").toString();
            Integer dbTabeCount=dbTableCountMap.get(dbName);
            if(dbTabeCount!=null){
               html.add("<tr> <td rowspan=\""+dbTabeCount+"\">"+dbName+"</td>");
                dbTableCountMap.remove(dbName);
            }
            html.add("<td>\n" +
                    "<pre> "+m.get("sourceTable").toString()+" <pre>\n" +
                    "</td>");
            html.add("<td>\n" +
                    "<pre> "+m.get("targetTable").toString()+" <pre>\n" +
                    "</td>");
            html.add("</tr>");
        }
        html.add("</table>");
        FileUtils.writeStringToFile(new File("d:\\DbComparedTest.html"), html.toString());

    }
}

对比效果如下

 


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值