基于Spring包扫描工具和MybatisPlus逆向工程组件的数据表自动同步机制

news2024/11/25 13:42:48

公司产品产出的项目较多。同步数据库表结构工作很麻烦。一个alter语句要跑到N个客户机上执行脚本。超级费时麻烦。介于此,原有方案是把增量脚本放到一resource包下,项目启动时执行逐行执行一次。但由于模块开发人员较多,总有那么一两个机灵鬼漏写脚本。加上项目分支的原因,导致更新客户表结构后埋雷,炸雷。投诉不断。因此本人开发了一款可靠、自动的表结构更新构件。

原理说明:
1、由于全部表OR映射实体采用了MyBatisPlus的@TableName,TableField注解,所以利用组件(https://blog.csdn.net/qq_37148232/article/details/131821497?spm=1001.2014.3001.5501),扫描出项目中所有带@TableName的实体类。然后解析出表名、字段以及自定义注解上的建表类型,建表长度,注释,默认值等。得到最新的表结构。
2、利用从MyBatisPlus逆向工程中扒出来的表结构查询工具。稍做封装,得到项目数据库当前的表结构。
3、对比最新的表结构和当前表结构。得到缺哪些表、缺哪些字段、哪些字段更新了、
哪些字段删了。
4、将对比结果生成可执行的alter、ceate、drop、modify语句。更新数据库。为保险起见,drop和modify默认不启用。
5、开机自动运行生成的语句集。更新表结构。

代码结构如下:
在这里插入图片描述
各类说明:
ColumnInfo:包扫描实体类后得到的字段信息封装。
CreateTableHandler:自动建表处理器。
DBJDBCType:java-jdbcType映射接口。
MySqlJDBCType:Mysql系列数据库类型映射支持
OtherJDBCTYpe:Oracle系列数据库映射支持。
JDBCSupport:类型映射支持
SchemaAnalyserAutoConfiguration:主配置类
SchemaAnalyserExecutor:自动建表执行入口
SchemaDefinition:扫描后得到的表和字段信息
SchemaDefinitionLoader:包扫描及全面目字段信息加载类
SchemaExistedDefinitionLoader:项目库表结构加载类
UpdateTableHandler:Alter语句处理类

主要类代码:

public class ColumnInfo {

    private Boolean isPrimary;

    private String columnName;

    private String type;

    public String toCreateColumn() {

        if (isPrimary) {
            return columnName + " " + type + " " + "primary key";
        } else {
            return columnName + " " + type;
        }
    }
}
public class CreateTableHandler {

    @Autowired
    private JDBCSupport jdbcSupport;

    public void createTable(SchemaDefinition schemaDefinition) {
        if (!FrameworkProperties.enableAutoAlterTableCreate) {
            return;
        }
        List<String> columns = schemaDefinition.getColumns();

        Map<String, ColumnName> columnContainer = schemaDefinition.getColumnContainer();
        Map<String, Field> propContainer = schemaDefinition.getPropContainer();

        List<ColumnInfo> columnInfos = new ArrayList<>();
        TableId tableId = schemaDefinition.getTableId();
        if (null != tableId) {
            ColumnInfo columnInfo = new ColumnInfo();
            columnInfo.setColumnName(tableId.value());
            columnInfo.setIsPrimary(true);
            columnInfo.setType(jdbcSupport.decideJDBCPrimaryType());
            columnInfos.add(columnInfo);
        }

        for (String column : columns) {
            ColumnName columnName = columnContainer.get(column);
            Field field = propContainer.get(column);
            String jdbcType = jdbcSupport.decideJDBCType(column, field, columnName);
            ColumnInfo columnInfo = new ColumnInfo();
            columnInfo.setType(jdbcType);
            columnInfo.setIsPrimary(false);
            columnInfo.setColumnName(column);
            columnInfos.add(columnInfo);
        }
        jdbcSupport.createTable(schemaDefinition.getTableName(), columnInfos);
    }
}
public interface DBJDBCType {

    static DBJDBCType matchJDBCType(String databaseType) {
        return databaseType.toLowerCase().contains("mysql") ? new MySqlJDBCType() : new OtherJDBCType();
    }

    String varcharType(int length);

    String intType();

    String longType();

    String booleanType();

    String dateType();

    String textType();
}

public class JDBCSupport implements InitializingBean {

    private final static String SQL_ADD_MYSQL = "alter table %s add %s %s %s comment '%s';";

    private final static String SQL_ADD_ORACLE = "alter table %s add %s %s %s;";
    private final static String SQL_COMMENT_ORACLE = "comment on table %s.%s is '%s';";

    private final static String SQL_MODIFY = "alter table %s modify %s %s;";
    private final static String SQL_CREATE = "create table %s (%s);";

    private DataSource dataSource;

    private String databaseProductName;
    private boolean isMysql;

    public JDBCSupport(DataSource dataSource) {
        this.dataSource = dataSource;
    }

    public void createTable(String tableName, List<ColumnInfo> columnInfos) {
        List<String> createColumns = ListUtils.list2list(columnInfos, ColumnInfo::toCreateColumn);
        String columnSqlItems = StrUtils.join(createColumns);
        String createSql = String.format(SQL_CREATE, tableName, columnSqlItems);
        executeSql(createSql);
    }

    public void addColumn(String tableName, String columnName, String type, Object defaultValue, String comment) {
        String sql;
        // 默认值
        String defaultValueSegment = "";
        if (StrUtils.isNotNull(defaultValue)) {
            if (defaultValue instanceof String) {
                defaultValueSegment = "default '" + defaultValue + "'";
            } else {
                if (!"-999".equals(String.valueOf(defaultValue))) {
                    defaultValueSegment = "default " + defaultValue;
                }
            }
        }
        // 注释
        comment = StrUtils.isNull(comment) ? "" : comment;
        if (isMysql) {
            sql = String.format(SQL_ADD_MYSQL, tableName, columnName, type, defaultValueSegment, comment);
            executeSql(sql);
        } else {
            sql = String.format(SQL_ADD_ORACLE, tableName, columnName, type, defaultValueSegment);
            String commentSql = String.format(SQL_COMMENT_ORACLE, tableName, columnName, comment);
            executeSql(sql);
            executeSql(commentSql);
        }


    }


    public void modifyColumn(String tableName, String columnName, String type) {
        String sql = String.format(SQL_MODIFY, tableName, columnName, type);
        executeSql(sql);
    }

    public String decideJDBCPrimaryType() {
        DBJDBCType dbjdbcType = DBJDBCType.matchJDBCType(databaseProductName);
        // 主键用60位字符
        return dbjdbcType.varcharType(60);
    }

    public String decideJDBCType(String columnName, Field field, ColumnName definition) {
        DBJDBCType dbjdbcType = DBJDBCType.matchJDBCType(databaseProductName);
        if (null != definition) {
            return chooseByColumnDefinition(definition, dbjdbcType);
        } else {
            return chooseByField(columnName, field, dbjdbcType);
        }
    }

    @Override
    public void afterPropertiesSet() {
        try (Connection connection = dataSource.getConnection()) {
            this.databaseProductName = connection.getMetaData().getDatabaseProductName();
            this.isMysql = "MySQL".equals(databaseProductName);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private String chooseByField(String columnName, Field field, DBJDBCType dbjdbcType) {
        if (null == field) {
            return dbjdbcType.varcharType(200);
        }
        String name = field.getName();
        Class<?> fieldType = field.getType();
        if (String.class.isAssignableFrom(fieldType)) {
            // 基于经验的一些合理猜测判断
            if (columnName.endsWith("_id")) {
                return dbjdbcType.varcharType(60);
            } else if (columnName.endsWith("_ids")) {
                return dbjdbcType.varcharType(500);
            } else if (name.equals("content")) {
                return dbjdbcType.varcharType(500);
            } else if (name.equals("createBy")) {
                return dbjdbcType.varcharType(60);
            } else if (name.equals("updateBy")) {
                return dbjdbcType.varcharType(60);
            } else if (name.equals("areaId")) {
                return dbjdbcType.varcharType(60);
            } else {
                return dbjdbcType.varcharType(200);
            }
        }
        if (Integer.class.isAssignableFrom(fieldType)) {
            // 基于经验的一些合理猜测判断
            if (columnName.startsWith("is_") || columnName.startsWith("has_")) {
                return dbjdbcType.booleanType();
            } else {
                return dbjdbcType.intType();
            }
        }

        if (Long.class.isAssignableFrom(fieldType)) {
            return dbjdbcType.longType();
        }

        if (Date.class.isAssignableFrom(fieldType)) {
            return dbjdbcType.dateType();
        }
        return dbjdbcType.varcharType(200);
    }

    private String chooseByColumnDefinition(ColumnName definition, DBJDBCType dbjdbcType) {
        if (definition.varcharColumn()) {
            return dbjdbcType.varcharType(definition.varcharLength());
        } else if (definition.booleanColumn()) {
            return dbjdbcType.booleanType();
        } else if (definition.intColumn()) {
            return dbjdbcType.intType();
        } else if (definition.longColumn()) {
            return dbjdbcType.longType();
        } else if (definition.dateColumn()) {
            return dbjdbcType.dateType();
        } else if (definition.textColumn()) {
            return dbjdbcType.textType();
        } else {
            return dbjdbcType.varcharType(definition.varcharLength());
        }
    }

    private void executeSql(String sql) {
        try (Connection connection = dataSource.getConnection();
             PreparedStatement preparedStatement = connection.prepareStatement(sql)
        ) {
            preparedStatement.execute();
        } catch (Exception e) {
            log.warn("sql[{}]执行异常", sql);
        }
    }
}
public class MySqlJDBCType implements DBJDBCType {
    @Override
    public String varcharType(int length) {
        return "varchar(" + length + ")";
    }

    @Override
    public String intType() {
        return "int";
    }

    @Override
    public String longType() {
        return "bigint";
    }

    @Override
    public String booleanType() {
        return "tinyint";
    }

    @Override
    public String dateType() {
        return "date";
    }

    @Override
    public String textType() {
        return "text";
    }
}
public class OtherJDBCType implements DBJDBCType {
    @Override
    public String varcharType(int length) {
        return "varchar2(" + (length * 2) + ")";
    }

    @Override
    public String intType() {
        return "number(10)";
    }

    @Override
    public String longType() {
        return "number(19)";
    }

    @Override
    public String booleanType() {
        return "number(1)";
    }

    @Override
    public String dateType() {
        return "date";
    }

    @Override
    public String textType() {
        return "text";
    }
}
@Configuration
@ConditionalOnProperty(prefix = "com.xxx.framework", name = "enable-auto-alter-table", havingValue = "true")
public class SchemaAnalyserAutoConfiguration {

    @Bean
    public JDBCSupport jdbcSupport(DataSource dataSource) {
        return new JDBCSupport(dataSource);
    }

    @Bean
    public CreateTableHandler createTableHandler() {
        return new CreateTableHandler();
    }

    @Bean
    public UpdateTableHandler updateTableHandler() {
        return new UpdateTableHandler();
    }

    @Bean
    public SchemaAnalyserExecutor schemaAnalyserRunner() {
        return new SchemaAnalyserExecutor();
    }

    @Bean
    @DependsOn("frameworkProperties") // 主要是读取系统类型用于一些判断,所以要依赖
    public SchemaDefinitionLoader schemaDefinitionLoader() {
        return new SchemaDefinitionLoader();
    }

    @Bean
    public SchemaExistedDefinitionLoader schemaExistedDefinitionLoader() {
        return new SchemaExistedDefinitionLoader();
    }
}

public class SchemaAnalyserExecutor implements EasySpringListener {

    @Autowired
    private CreateTableHandler createTableHandler;
    @Autowired
    private UpdateTableHandler updateTableHandler;
    @Autowired
    private SchemaDefinitionLoader schemaDefinitionLoader;
    @Autowired
    private SchemaExistedDefinitionLoader schemaExistedDefinitionLoader;

    @Override
    public void doBusiness(ApplicationContext applicationContext) {
        List<SchemaDefinition> projectSchemaDefinition = schemaDefinitionLoader.getProjectSchemaDefinition();
        Map<String, TableInfo> tableContainer = schemaExistedDefinitionLoader.findExistedTableInfo();

        generateDelete(tableContainer);
        // 对比已存在的表和字段,更新字段或新建表
        for (SchemaDefinition schemaDefinition : projectSchemaDefinition) {
            // 看表里存不存在该表的定义信息
            TableInfo tableInfo = tableContainer.get(schemaDefinition.getTableName());
            if (null != tableInfo) {
                try {
                    updateTableHandler.updateTable(schemaDefinition, tableInfo);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            } else {
                try {
                    createTableHandler.createTable(schemaDefinition);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }

    public void generateDelete(Map<String, TableInfo> tableContainer) {
        if (FrameworkProperties.enableGenerateDeleteScript) {
            Set<String> strings = tableContainer.keySet();
            List<String> tableNames = ZYListUtils.set2list(strings);
            tableNames.sort(Comparator.comparing(a -> a));
            List<String> deleteSqls = new ArrayList<>();
            tableNames.forEach(tableName -> {
                deleteSqls.add("delete from " + tableName + " ;");
            });

            FileUtils.writeLines(deleteSqls, "D://clear_" + ZYDateUtils.formart(new Date(), "yyyy-MM-dd-HH-mm-ss") + ".sql", "utf-8", true);
        }
    }

    @Override
    public int getOrder() {
        return 0;
    }
}

public class SchemaDefinition {

    private String tableName;

    private String tableComment;
    // 表格信息
    private TableName tableNameAnnotation;
    // 主键信息
    private TableId tableId;

    private List<String> columns = new ArrayList<>();
    // 字段属性定义
    private Map<String, Field> propContainer = new HashMap<>();
    // 字段描述信息
    private Map<String, ColumnName> columnContainer = new HashMap<>();
    // 字段定义信息
    private Map<String, TableField> fieldContainer = new HashMap<>();

    public void joinSchemaDefinition(SchemaDefinition schemaDefinition) {
        List<String> targetColumns = schemaDefinition.getColumns();
        Map<String, ColumnName> targetColumnContainer = schemaDefinition.getColumnContainer();
        Map<String, TableField> targetFieldContainer = schemaDefinition.getFieldContainer();
        for (String targetColumn : targetColumns) {
            if (!columns.contains(targetColumn)) {
                ColumnName columnName = targetColumnContainer.get(targetColumn);
                TableField tableField = targetFieldContainer.get(targetColumn);
                if (null != columnName && null != tableField) {
                    columns.add(targetColumn);
                    columnContainer.put(targetColumn, columnName);
                    fieldContainer.put(targetColumn, tableField);
                }
            }
        }


    }

    public SchemaDefinition(Class<?> aClass) {
        this.tableNameAnnotation = aClass.getAnnotation(TableName.class);
        // 表名
        this.tableName = tableNameAnnotation.value().toLowerCase();

        // 收集字段定义信息
        Field[] fields = ZYReflectUtils.getFields(aClass);
        for (Field field : fields) {
            field.setAccessible(true);
            // 主键字段
            TableId tableId = field.getAnnotation(TableId.class);
            if (null != tableId) {
                this.tableId = tableId;
                continue;
            }

            // 普通字段
            TableField tableField = field.getAnnotation(TableField.class);
            if (null == tableField) {
                continue;
            }
            if (!tableField.exist()) {
                continue;
            }
            String column = tableField.value().toLowerCase();
            // 字段集合
            columns.add(column);
            // 表格定义
            fieldContainer.put(column, tableField);
            // 字段反射属性
            propContainer.put(column, field);
            // 建表描述
            ColumnName columnName = field.getAnnotation(ColumnName.class);
            if (null != columnName) {
                columnContainer.put(column, columnName);
            }
        }
    }
}
public class SchemaDefinitionLoader implements InterestedClassAware {

    private List<SchemaDefinition> schemaDefinitions = new ArrayList<>();

    public List<SchemaDefinition> getProjectSchemaDefinition() {
        return schemaDefinitions;
    }

    @Override
    public boolean match(AnnotationMetadata annotationMetadata) {
        return annotationMetadata.hasAnnotation(TableName.class.getName());
    }

    @Override
    public void setClasses(Set<Class<?>> classes) {
        List<SchemaDefinition> definitions = new ArrayList<>();

        Map<String, TableCondition> tableConditionCache = new HashMap<>();
        for (Class<?> aClass : classes) {
            TableExplain tableExplain = aClass.getAnnotation(TableExplain.class);
            if (isNecessary(tableConditionCache, tableExplain, aClass)) {
                SchemaDefinition schemaDefinition = new SchemaDefinition(aClass);
                if (null != tableExplain) {
                    // 表的注释
                    schemaDefinition.setTableComment(tableExplain.value());
                }

                definitions.add(schemaDefinition);
            }
        }

        Map<String, List<SchemaDefinition>> schemaContainer = ZYListUtils.groupList(definitions, SchemaDefinition::getTableName);
        schemaContainer.forEach((schemaName, schemas) -> {
            if (schemas.size() == 1) {
                schemaDefinitions.add(schemas.get(GlobalConstant.FIRST));
            } else if (schemas.size() > 1) {
                SchemaDefinition schemaDefinition = schemas.get(GlobalConstant.FIRST);
                // 合并集合
                for (int i = 1; i < schemas.size(); i++) {
                    schemaDefinition.joinSchemaDefinition(schemas.get(i));
                }
                schemaDefinitions.add(schemaDefinition);
            }
        });
    }

    private boolean isNecessary(Map<String, TableCondition> tableConditionCache, TableExplain tableExplain, Class<?> aClass) {
        if (null == tableExplain) {
            return true;
        }

        if (tableExplain.exclude()) {
            return false;
        }

        Class<? extends TableCondition> condition = tableExplain.condition();
        String name = condition.getName();
        TableCondition tableCondition = tableConditionCache.get(name);
        if (null == tableCondition) {
            tableCondition = ReflectUtils.newInstance(condition);
            tableConditionCache.put(name, tableCondition);
        }
        return tableCondition.isNecessary(aClass);

    }
}

public class SchemaExistedDefinitionLoader {

    @Autowired
    private DataSourceProperties dataSourceProperties;
    @Autowired
    private DataSource dataSource;

    @SneakyThrows
    public Map<String, TableInfo> findExistedTableInfo() {
        DataSourceConfig dataSourceConfig = new DataSourceConfig();
        dataSourceConfig.setDriverName(dataSourceProperties.getDriverClassName());
        dataSourceConfig.setPassword(dataSourceProperties.getPassword());
        dataSourceConfig.setUsername(dataSourceProperties.getUsername());
        String url = dataSourceProperties.getUrl();
        dataSourceConfig.setUrl(url);

        this.connection = dataSourceConfig.getConn();
        dataSourceConfig.setSchemaName(this.connection.getSchema());
        this.dataSourceConfig = dataSourceConfig;
        if (url.contains("kingbase8")) {
            this.dbQuery = new OracleQuery();
        } else {
            this.dbQuery = dataSourceConfig.getDbQuery();
        }

        this.strategyConfig = new StrategyConfig();
        this.globalConfig = new GlobalConfig();
        List<TableInfo> tablesInfo = getTablesInfo();
        return ZYListUtils.groupModel(tablesInfo, TableInfo::getName);
        // 表名全改成小写

    }


    private IDbQuery dbQuery;

    private DataSourceConfig dataSourceConfig;

    private Connection connection;

    private GlobalConfig globalConfig;

    private StrategyConfig strategyConfig;

    private List<TableInfo> getTablesInfo() {
        //所有的表信息
        List<TableInfo> tableList = new ArrayList<>();
        //不存在的表名
        PreparedStatement preparedStatement = null;
        try {
            String tablesSql = dbQuery.tablesSql();
            if (DbType.POSTGRE_SQL == dbQuery.dbType()) {
                String schema = dataSourceConfig.getSchemaName();
                if (schema == null) {
                    //pg默认schema=public
                    schema = "public";
                    dataSourceConfig.setSchemaName(schema);
                }
                tablesSql = String.format(tablesSql, schema);
            }
            //oracle数据库表太多,出现最大游标错误
            else if (DbType.ORACLE == dbQuery.dbType()) {
                String schema = dataSourceConfig.getSchemaName();
                //oracle默认用户的schema=username
                if (schema == null) {
                    schema = dataSourceConfig.getUsername().toUpperCase();
                    dataSourceConfig.setSchemaName(schema);
                }
                tablesSql = String.format(tablesSql, schema);
            }
            preparedStatement = connection.prepareStatement(tablesSql);
            ResultSet results = preparedStatement.executeQuery();
            TableInfo tableInfo;
            while (results.next()) {
                String tableName = results.getString(dbQuery.tableName());
                if (StringUtils.isNotEmpty(tableName)) {
                    String tableComment = results.getString(dbQuery.tableComment());
                    if ("VIEW".equalsIgnoreCase(tableComment)) {
                        // 跳过视图
                        continue;
                    }
                    tableInfo = new TableInfo();
                    tableInfo.setName(tableName.toLowerCase());
                    tableInfo.setComment(tableComment);
                    tableList.add(tableInfo);
                } else {
                    System.err.println("当前数据库为空!!!");
                }
            }
            tableList.forEach(ti -> convertTableFields(ti, strategyConfig.getColumnNaming()));
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            // 释放资源
            try {
                if (preparedStatement != null) {
                    preparedStatement.close();
                }
                if (connection != null) {
                    connection.close();
                }
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        return tableList;
    }

    private TableInfo convertTableFields(TableInfo tableInfo, NamingStrategy strategy) {
        boolean haveId = false;
        List<TableField> fieldList = new ArrayList<>();
        try {
            String tableFieldsSql = dbQuery.tableFieldsSql();
            if (DbType.POSTGRE_SQL == dbQuery.dbType()) {
                tableFieldsSql = String.format(tableFieldsSql, dataSourceConfig.getSchemaName(), tableInfo.getName());
            } else if (DbType.ORACLE == dbQuery.dbType()) {
                tableFieldsSql = String.format(tableFieldsSql.replace("#schema", dataSourceConfig.getSchemaName()), tableInfo.getName());
            } else {
                tableFieldsSql = String.format(tableFieldsSql, tableInfo.getName());
            }
            PreparedStatement preparedStatement = connection.prepareStatement(tableFieldsSql);
            ResultSet results = preparedStatement.executeQuery();
            while (results.next()) {
                TableField field = new TableField();
                field.setName(results.getString(dbQuery.fieldName().toLowerCase()));
                field.setType(results.getString(dbQuery.fieldType()));
                field.setColumnType(dataSourceConfig.getTypeConvert().processTypeConvert(globalConfig, field.getType()));
                field.setComment(results.getString(dbQuery.fieldComment()));
                fieldList.add(field);
            }
        } catch (SQLException e) {
            System.err.println("SQL Exception:" + e.getMessage());
        }
        tableInfo.setFields(fieldList);
        return tableInfo;
    }
}
public class UpdateTableHandler {

    @Autowired
    private JDBCSupport jdbcSupport;

    public void updateTable(SchemaDefinition schemaDefinition, TableInfo tableInfo) {
        if (!FrameworkProperties.enableAutoAlterTableAddColumn && !FrameworkProperties.enableAutoAlterTableModifyColumn) {
            return;
        }

        List<String> columns = schemaDefinition.getColumns();
        List<TableField> commonFields = tableInfo.getFields();

        Map<String, TableField> existsColumnContainer = ZYListUtils.groupModel(commonFields, TableField::getName);
        // 列的定义
        Map<String, ColumnName> columnContainer = schemaDefinition.getColumnContainer();
        // 列的字段描述
        Map<String, Field> propContainer = schemaDefinition.getPropContainer();

        String tableName = tableInfo.getName();
        for (String column : columns) {
            // 列的定义注解
            ColumnName columnName = columnContainer.get(column);
            // 列属性的反射类型
            Field field = propContainer.get(column);
            // 决定jdbc现有的类型
            String jdbcType = jdbcSupport.decideJDBCType(column, field, columnName);
            if (!existsColumnContainer.containsKey(column)) {
                // 添加字段
                if (FrameworkProperties.enableAutoAlterTableAddColumn) {
                    Object defaultValue = null;
                    String comment = "";
                    if (null != columnName && null != field) {
                        boolean isVarchar = String.class.isAssignableFrom(field.getType());
                        defaultValue = isVarchar ? columnName.varcharDefaultValue() : columnName.intDefaultValue();
                        comment = columnName.value();
                    }
                    jdbcSupport.addColumn(tableName, column, jdbcType, defaultValue, comment);
                }
            } else {
                // 更新字段
                TableField existsTableField = existsColumnContainer.get(column);
                if (compareAndNecessaryModify(column, columnName, field, existsTableField)) {
                    if (FrameworkProperties.enableAutoAlterTableModifyColumn) {
                        jdbcSupport.modifyColumn(tableName, column, jdbcType);
                    }
                }
            }
        }

    }

    // 比对下新旧数据库,看字段是否需要modify
    private boolean compareAndNecessaryModify(String column, ColumnName columnName, Field field, TableField existsTableField) {
        // 主要是字段类型跟长度
        String type = existsTableField.getType();
        String jdbcType = jdbcSupport.decideJDBCType(column, field, columnName);
        return !type.equals(jdbcType);
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/794666.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

大数据课程D2——hadoop的概述

文章作者邮箱&#xff1a;yugongshiyesina.cn 地址&#xff1a;广东惠州 ▲ 本章节目的 ⚪ 了解hadoop的定义和特点&#xff1b; ⚪ 掌握hadoop的基础结构&#xff1b; ⚪ 掌握hadoop的常见命令&#xff1b; ⚪ 了解hadoop的执行流程&#xff1b; 一、简介 1…

ElasticSearch Window Linux部署

文章目录 一、Window 集群部署二、Linux 单节点部署三、Linux 集群部署 一、Window 集群部署 创建 elasticsearch-cluster 文件夹&#xff0c;在内部复制三个elasticsearch服务 修改集群文件目录中每个节点的 config/elasticsearch.yml 配置文件 # -----------------------…

[Linux] 初识应用层协议: 序列化与反序列化、编码与解码、jsoncpp简单使用...

写在应用层之前 有关Linux网络, 之前的文章已经简单演示介绍了UDP、TCP套接字编程 相关文章: [Linux] 网络编程 - 初见UDP套接字编程: 网络编程部分相关概念、TCP、UDP协议基本特点、网络字节序、socket接口使用、简单的UDP网络及聊天室实现… [Linux] 网络编程 - 初见TCP套接…

大气预报模式:非结构化质心Voronoi网格MPAS跨尺度、可变分辨率模式应用

查看原文>>>最新MPAS跨尺度、可变分辨率模式实践技术应用及典型案例分析 目录 专题一、MPAS 模式基本信息 专题二、MPAS 代码获取及结构 专题三、MPAS 移植、编译及运行实践 专题四、MPAS 全球均匀网格的运行 专题五、MPAS 全球非均匀网格的运行 专题六、MPAS …

mysql的一些知识整理

这里整理一些mysql相关的知识点&#xff0c;是自己不太熟悉的内容 varchar(n) 中 n 最大取值为多少 MySQL 规定除了 TEXT、BLOBs 这种大对象类型之外&#xff0c;其他所有的列&#xff08;不包括隐藏列和记录头信息&#xff09;占用的字节长度加起来不能超过 65535 个字节。 …

全志F1C200S嵌入式驱动开发(触摸屏驱动)

【 声明:版权所有,欢迎转载,请勿用于商业用途。 联系信箱:feixiaoxing @163.com】 触摸屏一般有两种,一种是电阻触摸屏,一种是电容触摸屏。前者需要自己买一颗i2c的信号读取芯片,用的比较多的是ns2009。后者自身集成了读取芯片,用的比较多的是gt911。正好之前测…

大数据课程D1——hadoop的初识

文章作者邮箱&#xff1a;yugongshiyesina.cn 地址&#xff1a;广东惠州 ▲ 本章节目的 ⚪ 了解大数据的概念&#xff1b; ⚪ 了解大数据的部门结构&#xff1b; ⚪ 了解hadoop的定义&#xff1b; ⚪ 了解hadoop的发展史&#xff1b; 一、大数据简介 1. 概述…

Spring Alibaba Sentinel实现集群限流demo

1.背景 1.什么是单机限流&#xff1f; 小伙伴们或许遇到过下图这样的限流配置 又或者是这样的Nacos动态配置限流规则&#xff1a; 以上这些是什么限流&#xff1f;没错&#xff0c;就是单机限流&#xff0c;那么单机限流有什么弊端呢&#xff1f; 假设我们集群部署3台机器&a…

gensim conherence model C_V 值与其他指标负相关BUG

在我用gensim3.8.3 conherence model分析京东评论主题模型时&#xff0c; C_V 与npmi、u_mass出现了强烈的皮尔逊负相关&#xff1a; 这些地方也反映了类似问题&#xff1a; https://github.com/dice-group/Palmetto/issues/12 https://github.com/dice-group/Palmetto/issue…

Python:使用openpyxl读取Excel文件转为json数据

文档 https://openpyxl.readthedocs.io/en/stable/https://pypi.org/project/openpyxl/ 安装 pip install openpyxl环境 $ python --version Python 3.7.0读取文件示例&#xff1a;将Excel文件读取为json数据 有如下一个文件 data.xlsx 实现代码 # -*- coding: utf-8 -…

IPIDEA参展ChinaJoy!探索未来创新科技的峰会之旅

中国最大的国际数码互动娱乐展会ChinaJoy即将于7月28日在上海举行&#xff0c;届时将聚集全球来自22个国家和地区的领先科技公司、创业者和技术专家&#xff0c;为参观者呈现一系列引人入胜的展览和活动。而IPIDEA作为参展商之一&#xff0c;将为参观者带来一场关于数字科技的奇…

C++笔记之从使用函数指针和typedef到使用std::function和using

C笔记之从使用函数指针和typedef到使用std::function和using code review! 文章目录 C笔记之从使用函数指针和typedef到使用std::function和using1.回顾函数指针的用法2.函数指针结合typedef3.使用std::function来重写代码4.在使用std::function时&#xff0c;你无需显式声明…

【Nodejs】跨域

1.什么是跨域 跨域&#xff0c;是指浏览器不能执行其他网站的脚本。它是由浏览器的同源策略造成的&#xff0c;是浏览器对JavaScript实施的安全限制。浏览器从一个域名的网页去请求另一个域名的资源时&#xff0c;出现域名、端口、协议任一不同&#xff0c;都属于跨域。 同源策…

Spring Cloud【为什么需要监控系统、Prometheus环境搭建、Grafana环境搭建 、微服务应用接入监控 】(十七)

目录 全方位的监控告警系统_为什么需要监控系统 全方位的监控告警系统_Prometheus环境搭建 全方位的监控告警系统_Grafana环境搭建 全方位的监控告警系统_微服务应用接入监控 全方位的监控告警系统_为什么需要监控系统 前言 一个服务上线了后&#xff0c;你想知道这个服…

PostgreSQL-Character with value 0x09 must be escaped.

在使用json相关函数时&#xff0c;报了这个错&#xff1a; Character with value 0x09 must be escaped.中文即使&#xff1a;值为0x09的字符必须转义。 找了下这个0x09 这个ASCII的值&#xff0c;是水平制表符。那这应该是因为json不支持换行导致的&#xff0c;我们将水平制…

spring-websocket在SpringBoot(包含SpringSecurity)项目中的导入

✅作者简介&#xff1a;大家好&#xff0c;我是 Meteors., 向往着更加简洁高效的代码写法与编程方式&#xff0c;持续分享Java技术内容。 &#x1f34e;个人主页&#xff1a;Meteors.的博客 &#x1f96d;本文内容&#xff1a;spring-websocket在SpringBoot(包含SpringSecurity…

移动云携手启明星辰打造云网全域安全能力 提供全方位网络安全防护和风险控制服务

为满足大众安全用云、智慧用云的需求&#xff0c;中国移动云能力中心与启明星辰强强联合打造移动云|星辰安全—云网全域安全能力。此次合作深度融合信息技术与业务运营&#xff0c;提供全方位的网络安全防护和风险控制服务&#xff0c;满足国家合规要求和大众用云需求&#xff…

从小白到大神之路之学习运维第68天-------Nginx企业级优化与防盗链

第三阶段基础 时 间&#xff1a;2023年7月26日 参加人&#xff1a;全班人员 内 容&#xff1a; Nginx企业级优化与防盗链 目录 一、配置Nginx隐藏版本号 二、修改Nginx用户与组 ​三、配置Nginx网页缓存时间 四、实现Nginx的日志切割 五、配置Nginx实现连接超时 六…

图为科技T501赋能工业机器人 革新传统工业流程

工业机器人已成为一个国家制造技术与科技水平的重要衡量标准&#xff0c;在2019年&#xff0c;中国工业机器人的组装量与产量均位居了全球首位。 当前&#xff0c;工业机器人被广泛用于电子、物流、化工等多个领域之中&#xff0c;是一种通过电子科技和机械关节制作出来的智能机…

让婚礼策划展示小程序成为你的必备利器

在当今互联网时代&#xff0c;微信小程序已经成为了很多企业和个人展示自己产品和服务的重要渠道。如果你想学习微信小程序开发&#xff0c;下面将为你介绍一些基本步骤。 首先&#xff0c;你需要注册并登录一个第三方小程序制作平台&#xff0c;比如乔拓云平台。这些平台提供了…