Clase de herramienta Java: SqlFileCompareUtils (comparar tabla de base de datos y cambios de campo)

【Antecedentes】

En el proceso de desarrollo real, generalmente tenemos un entorno de desarrollo, un entorno de prueba y un entorno de producción.

En estos entornos, generalmente hay bases de datos correspondientes. Dado que cada nuevo requisito se prueba en el entorno de prueba, la estructura de la base de datos de diferentes entornos será diferente.

Cuando las funciones de la nueva versión se prueban en el entorno de prueba, las nuevas funciones deben actualizarse al entorno de producción. En este momento, la estructura de la base de datos del entorno de producción debe ser coherente con la estructura de la base de datos del entorno de prueba nuevamente. para garantizar el uso normal de las nuevas funciones.

【Comparación de bases de datos】

Cuando queremos saber los cambios en las dos bases de datos, si comparamos cada tabla y cada campo, cuando los cambios son grandes, esta será una experiencia muy desagradable, no solo requiere mucho tiempo y mano de obra, y es propensa a errores. . Así que escribí una clase de herramienta SqlFileCompareUtils para la comparación de campos de base de datos (vea el código fuente al final).

【Instrucciones】

(1) Primero exporte el archivo sql (solo la estructura) de la base de datos de cada entorno;

 (2) Luego coloque cada archivo sql exportado en el directorio raíz de cualquier proyecto.

 (3) Luego abra la clase de herramienta SqlFileCompareUtils (consulte el código fuente al final) y modifique las dos constantes en la clase de herramienta al nombre de archivo sql del entorno correspondiente.

 (4) En el aspecto principal de la clase de ejecución, la consola imprimirá que la estructura de la base de datos ha cambiado y el resultado es el siguiente (muestra), para que pueda agregar claramente las tablas y campos correspondientes al entorno de producción de acuerdo con las siguientes indicaciones.

Hay 17 cambios en total, como sigue:
[1] Nuevo campo en la tabla z_dept: fillStatus: smallint(2)
[2] Nuevo campo en la tabla z_dept: syncStatus: smallint(6)
[3] Nuevo campo en la tabla z_dept_month_labor: transProject : char (1)
[4] Nuevos campos en la tabla z_dept_month_labor: transDept : char(1)
[5] Cambios en los campos de la tabla z_project: piCode : varchar(255) -> varchar(50)
[6] Cambios en los campos en la tabla z_project: código: varchar (255) -> varchar (50)
[7] cambios de campo de la tabla z_project: operanSn: varchar (255) -> varchar (50)
[8] cambios de campo de la tabla z_project: finName: varchar (255) -> varchar(50)
[9 ] Cambios en el campo de la tabla z_project: finCode : varchar(255) -> varchar(50)
[10] Cambios en el campo de la tabla z_project: nombre : varchar(255) -> varchar(50)
[ 11] Cambios en el campo de la tabla z_project: operatorName: varchar(255) -> varchar(50)
[12] Cambios en el campo de la tabla z_project: syncStatus: varchar(255) -> varchar(5)
[13] Nuevo campo en la tabla z_project: isTransfer: char(1)
[14] Nueva tabla: z_project_log
[15] Nueva tabla: z_sow_log
[16] Nueva tabla: z_dept_user
[17] Nueva tabla: z_sow

[código fuente de la herramienta]

package com.zyq.test;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * 比较两个SQL文件,是否存在表变化和字段变化
 * 
 * @author zyq
 * @since 2021/11/04
 */
public class SqlFileCompareUtils {

    // 源 sql 文件(测试环境)
    public static String sqlFileNameFrom = "zyq_test.sql";
    // 目标 sql 文件(正式环境)
    public static String sqlFileNameTo = "zyq_live.sql";

    public static void main(String[] args) {
        printDifference();
    }

    public static void printDifference() {
        String msg = checkFile();
        if (msg != null) {
            System.err.println(msg);
            return;
        }
        // 获取源 sql 文件的表字段信息
        Map<String, Map<String, String>> fromMap = getTableMap(sqlFileNameFrom);
        // 获取目标 sql 文件的表字段信息
        Map<String, Map<String, String>> toMap = getTableMap(sqlFileNameTo);
        // 比较两个 sql 文件的字段信息
        List<String> differenceList = getDifferenceList(fromMap, toMap);
        if (differenceList.isEmpty()) {
            System.out.println("表和字段无变化");
            return;
        }
        int size = differenceList.size();
        System.out.println("共变化 " + size + "处,具体如下:");
        for (int i = 0; i < size; i++) {
            System.out.println(String.format("【%s】%s", (i + 1), differenceList.get(i)));
        }
    }

    private static List<String> getDifferenceList(Map<String, Map<String, String>> fromMap,
            Map<String, Map<String, String>> toMap) {
        List<String> list = new ArrayList<String>();
        Set<String> toTableSet = toMap.keySet();
        for (String tableName : toTableSet) {
            Map<String, String> fromFieldMap = fromMap.get(tableName);
            // 如果目标文件有该表,源文件没有该表,则表已被删除,冗余
            if (fromFieldMap == null) {
                list.add("多余表:" + tableName);
            }
            // 继续比较表的字段
            Map<String, String> toFieldMap = toMap.get(tableName);
            List<String> fieldList = getDifferenceFieldList(tableName, fromFieldMap, toFieldMap);
            if (!fieldList.isEmpty()) {
                list.addAll(fieldList);
            }
        }
        // 新增表
        Set<String> fromTableSet = fromMap.keySet();
        fromTableSet.removeAll(toTableSet);
        for (String tableName : fromTableSet) {
            list.add("新增表:" + tableName);
        }
        return list;
    }

    private static List<String> getDifferenceFieldList(String tableName, Map<String, String> fromMap,
            Map<String, String> toMap) {
        List<String> list = new ArrayList<String>();
        Set<String> toFiledSet = toMap.keySet();
        for (String filedName : toFiledSet) {
            String fromFileType = fromMap.get(filedName);
            // 如果目标文件表有该字段,源文件表没有该字段,则该字段已被删除,冗余
            if (fromFileType == null) {
                list.add("%s 表多余字段:" + fromFileType);
                continue;
            }
            // 继续比较字段类型
            String toFileType = toMap.get(filedName);
            if (!fromFileType.equals(toFileType)) {
                list.add(String.format("%s 表字段变化:%s : %s -> %s", tableName, filedName, toFileType, fromFileType));
            }
        }
        // 新增字段
        Set<String> fromFiledSet = fromMap.keySet();
        fromFiledSet.removeAll(toFiledSet);
        for (String fromFiledName : fromFiledSet) {
            list.add(String.format("%s 表新增字段:%s : %s", tableName, fromFiledName, fromMap.get(fromFiledName)));
        }
        return list;
    }

    private static Map<String, Map<String, String>> getTableMap(String fileName) {
        String sqlFrom = getFileContent(fileName);
        Map<String, Map<String, String>> map = new HashMap<String, Map<String, String>>();
        // 读取 sql 文件的所有行
        String[] lines = sqlFrom.split("\r\n");
        String tableName = null;
        for (String line : lines) {
            String trimLine = line.trim();
            // 以【CREATE TABLE】为开头的,则为表名
            if (trimLine.startsWith("CREATE TABLE")) {
                // 然后去掉 CREATE TABLE、`、( 即可获取表名
                tableName = trimLine.replaceAll("CREATE TABLE|`|\\(", "").trim();
                map.put(tableName, new HashMap<String, String>());
                continue;
            }
            // 以 ` 开头的,则为字段
            if (trimLine.startsWith("`")) {
                // 第 1 个 ` 和第 2 个 ` 之间的则为字段名
                String fieldName = getSplintIndexValue(trimLine, "`", 1);
                // 按 [空格] 拆分的第2个为字段类型
                String fieldType = getSplintIndexValue(trimLine, " ", 2);
                map.get(tableName).put(fieldName, fieldType);
            }
        }
        return map;
    }

    private static String getSplintIndexValue(String s, String regex, int index) {
        String[] strs = s.split(regex);
        int idx = 0;
        for (String str : strs) {
            if (!str.isEmpty()) {
                idx++;
            }
            if (idx == index) {
                return str;
            }
        }
        return "";
    }

    private static boolean isEmpty(String s) {
        return s == null || s.isEmpty();
    }

    private static String checkFile() {
        if (isEmpty(sqlFileNameFrom)) {
            return "源文件名称不能为空";
        }
        if (!sqlFileNameFrom.endsWith(".sql")) {
            return "源文件不是sql文件";
        }
        File from = new File(sqlFileNameFrom);
        if (!from.exists()) {
            return "源文件不存在于工程根目录下";
        }
        if (isEmpty(sqlFileNameTo)) {
            return "目标文件名称不能为空";
        }
        if (!sqlFileNameTo.endsWith(".sql")) {
            return "目标文件不是sql文件";
        }
        File to = new File(sqlFileNameTo);
        if (!to.exists()) {
            return "目标文件不存在于工程根目录下";
        }
        return null;
    }

    private static String getFileContent(String fileName) {
        File file = new File(fileName);
        try (FileInputStream fis = new FileInputStream(file)) {
            byte[] b = new byte[(int) file.length()];
            fis.read(b);
            return new String(b, "UTF-8");
        } catch (IOException e) {
            e.printStackTrace();
        }
        return "";
    }

}

Supongo que te gusta

Origin blog.csdn.net/sunnyzyq/article/details/121142302
Recomendado
Clasificación