GBase 8s
其他
文章

GBASE 8s mybatis-plus代码生成获取表注释和字段注释

发表于2025-08-01 12:30:47241次浏览3个评论

mybatis-plus代码生成器相关配置,具体说明可以参见mybatis-plus文档,在dataSourceConfig:

  .dataSourceConfig(builder -> builder
                        .driverClassName("com.gbasedbt.jdbc.Driver")
                        .databaseQueryClass(SQLQuery.class)
                        .dbQuery(new Gbase8sQuery())
                        .typeConvert(new Gbase8sTypeConvert())
                )

主要核心读取注释在Gbase8sQuery文件。类型转换在Gbase8sTypeConvert文件内。

以下为相关文件代码:

文件:Gbase8sQuery


import com.baomidou.mybatisplus.generator.config.querys.AbstractDbQuery;

public class Gbase8sQuery extends AbstractDbQuery {
    @Override
    public String tablesSql() {
        return "select c.comments,t.* from systables t left join SYSCOMMS c on c.tabid = t.tabid where t.tabid > 99";
    }

    @Override
    public String tableFieldsSql() {
        return "SELECT " +
                "    a.tabname, " +
                "    b.colname, " +
                "    b.coltype, " +
                "    CASE b.colname " +
                "        WHEN 'id' THEN 'PRI' " +
                "    END AS key, " +
                "    b.coltypename, " +
                "    c.comments, " +
                "    b.colno " +
                "FROM " +
                "    systables a " +
                "LEFT JOIN syscolumnsext b " +
                "    ON a.tabid = b.tabid " +
                "LEFT JOIN syscolcomments c " +
                "    ON c.tabname = a.tabname AND c.colname = b.colname " +
                "WHERE " +
                "    a.tabid > 99 " +
                "    AND a.tabtype = 'T' and a.tabname = '%s' " +
                "ORDER BY " +
                "    a.tabname, b.colno;";
    }

    @Override
    public String tableName() {
        return "tabname";
    }

    @Override
    public String tableComment() {
        return "comments";
    }

    @Override
    public String fieldName() {
        return "colname";
    }

    @Override
    public String fieldType() {
        return "coltypename";
    }

    @Override
    public String fieldComment() {
        return "comments";
    }

    @Override
    public String fieldKey() {
        return "key";
    }
}

文件:Gbase8sTypeConvert(类型对应可能不全,常用的都包含了,其他可自行扩展)


import com.baomidou.mybatisplus.generator.config.GlobalConfig;
import com.baomidou.mybatisplus.generator.config.ITypeConvert;
import com.baomidou.mybatisplus.generator.config.rules.DbColumnType;
import com.baomidou.mybatisplus.generator.config.rules.IColumnType;

import static com.baomidou.mybatisplus.generator.config.rules.DbColumnType.*;
import static com.dsicsoft.core.generate.Gbase8sTypeConverts.contains;
import static com.dsicsoft.core.generate.Gbase8sTypeConverts.containsAny;

/**
 * MYSQL 数据库字段类型转换
 * bit类型数据转换 bit(1) -> Boolean类型  bit(2->64)  -> Byte类型
 * <p>
 * 查看使用的类型方便添加转换器
 * SELECT b.coltypename, COUNT(*) AS column_count FROM systables a LEFT JOIN syscolumnsext b ON a.tabid = b.tabid LEFT JOIN syscolcomments c ON c.tabname = a.tabname AND c.colname = b.colname WHERE a.tabid > 99 AND a.tabtype = 'T' GROUP BY b.coltypename ORDER BY b.coltypename;
 *
 * @author hubin, hanchunlin, xiaoliang
 * @since 2017-01-20
 */
public class Gbase8sTypeConvert implements ITypeConvert {
    public static final Gbase8sTypeConvert INSTANCE = new Gbase8sTypeConvert();

    /**
     * {@inheritDoc}
     */
    @Override
    public IColumnType processTypeConvert(GlobalConfig config, String fieldType) {
        return Gbase8sTypeConverts.use(fieldType)
                .test(contains("serial").then(LONG))
                .test(containsAny("char", "varchar", "text", "json", "enum").then(STRING))
                .test(contains("bigint").then(LONG))
                .test(containsAny("tinyint(1)", "bit(1)").then(BOOLEAN))
                .test(contains("bit").then(BYTE))
                .test(containsAny("int", "integer").then(INTEGER))
                .test(contains("decimal").then(BIG_DECIMAL))
                .test(contains("clob").then(STRING))
                .test(contains("blob").then(STRING))
                .test(contains("binary").then(BYTE_ARRAY))
                .test(contains("float").then(FLOAT))
                .test(contains("double").then(DOUBLE))
                .test(containsAny("date", "time", "year").then(t -> toDateType(config, t)))
                .or(STRING);
    }

    /**
     * 转换为日期类型
     *
     * @param config 配置信息
     * @param type   类型
     * @return 返回对应的列类型
     */
    public static IColumnType toDateType(GlobalConfig config, String type) {
        String dateType = type.replaceAll("\\(\\d+\\)", "");
        switch (config.getDateType()) {
            case ONLY_DATE:
                return DbColumnType.DATE;
            case SQL_PACK:
                switch (dateType) {
                    case "date":
                    case "year":
                        return DbColumnType.DATE_SQL;
                    case "time":
                        return DbColumnType.TIME;
                    default:
                        return DbColumnType.TIMESTAMP;
                }
            case TIME_PACK:
                switch (dateType) {
                    case "date":
                        return DbColumnType.LOCAL_DATE;
                    case "time":
                        return DbColumnType.LOCAL_TIME;
                    case "year":
                        return DbColumnType.YEAR;
                    default:
                        return DbColumnType.LOCAL_DATE_TIME;
                }
        }
        return STRING;
    }

}

文件:Gbase8sTypeConverts

import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.generator.config.ITypeConvert;
import com.baomidou.mybatisplus.generator.config.converts.*;
import com.baomidou.mybatisplus.generator.config.converts.select.BranchBuilder;
import com.baomidou.mybatisplus.generator.config.converts.select.Selector;
import com.baomidou.mybatisplus.generator.config.rules.IColumnType;

/**
 * 该注册器负责注册并查询类型注册器
 *
 * @author nieqiuqiu, hanchunlin
 * @since 3.3.1
 */
public class Gbase8sTypeConverts {

    /**
     * 查询数据库类型对应的类型转换器
     *
     * @param dbType 数据库类型
     * @return 返回转换器
     */
    public static ITypeConvert getTypeConvert(DbType dbType) {
        switch (dbType) {
            case ORACLE:
                return OracleTypeConvert.INSTANCE;
            case DB2:
                return DB2TypeConvert.INSTANCE;
            case DM:
            case GAUSS:
                return DmTypeConvert.INSTANCE;
            case KINGBASE_ES:
                return KingbaseESTypeConvert.INSTANCE;
            case OSCAR:
                return OscarTypeConvert.INSTANCE;
            case MYSQL:
            case MARIADB:
                return MySqlTypeConvert.INSTANCE;
            case POSTGRE_SQL:
                return PostgreSqlTypeConvert.INSTANCE;
            case SQLITE:
                return SqliteTypeConvert.INSTANCE;
            case SQL_SERVER:
                return SqlServerTypeConvert.INSTANCE;
            case FIREBIRD:
                return FirebirdTypeConvert.INSTANCE;
            case CLICK_HOUSE:
                return ClickHouseTypeConvert.INSTANCE;
        }
        return null;
    }

    /**
     * 使用指定参数构建一个选择器
     *
     * @param param 参数
     * @return 返回选择器
     */
    static Selector<String, IColumnType> use(String param) {
        return new Selector<>(param.toLowerCase());
    }

    /**
     * 这个分支构建器用于构建用于支持 {@link String#contains(CharSequence)} 的分支
     *
     * @param value 分支的值
     * @return 返回分支构建器
     * @see #containsAny(CharSequence...)
     */
    static BranchBuilder<String, IColumnType> contains(CharSequence value) {
        return BranchBuilder.of(s -> s.contains(value));
    }

    /**
     * @see #contains(CharSequence)
     */
    static BranchBuilder<String, IColumnType> containsAny(CharSequence... values) {
        return BranchBuilder.of(s -> {
            for (CharSequence value : values) {
                if (s.contains(value)) {
                    return true;
                }
            }
            return false;
        });
    }
}

文件:Gbase8sDatabaseQuery

import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.generator.config.DataSourceConfig;
import com.baomidou.mybatisplus.generator.config.builder.ConfigBuilder;
import com.baomidou.mybatisplus.generator.config.builder.Entity;
import com.baomidou.mybatisplus.generator.config.po.TableField;
import com.baomidou.mybatisplus.generator.config.po.TableInfo;
import com.baomidou.mybatisplus.generator.config.rules.IColumnType;
import com.baomidou.mybatisplus.generator.jdbc.DatabaseMetaDataWrapper;
import com.baomidou.mybatisplus.generator.query.AbstractDatabaseQuery;
import com.baomidou.mybatisplus.generator.type.ITypeConvertHandler;
import com.baomidou.mybatisplus.generator.type.TypeRegistry;
import org.jetbrains.annotations.NotNull;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * 元数据查询数据库信息.
 *
 * @author nieqiurong 2022/5/11.
 * @see ITypeConvertHandler 类型转换器(如果默认逻辑不能满足,可实现此接口重写类型转换)
 * <p>
 * 测试通过的数据库:H2、Mysql-5.7.37、Mysql-8.0.25、PostgreSQL-11.15、PostgreSQL-14.1、Oracle-11.2.0.1.0、DM8
 * </p>
 * <p>
 * FAQ:
 * 1.Mysql无法读取表注释: 链接增加属性 remarks=true&useInformationSchema=true 或者通过{@link DataSourceConfig.Builder#addConnectionProperty(String, String)}设置
 * 2.Oracle无法读取注释: 增加属性remarks=true,也有些驱动版本说是增加remarksReporting=true {@link DataSourceConfig.Builder#addConnectionProperty(String, String)}
 * </p>
 * @since 3.5.3
 */
public class Gbase8sDatabaseQuery extends AbstractDatabaseQuery {

    private final TypeRegistry typeRegistry;
    protected final DatabaseMetaDataWrapper databaseMetaDataWrapper;

    public Gbase8sDatabaseQuery(@NotNull ConfigBuilder configBuilder) {
        super(configBuilder);
        typeRegistry = new TypeRegistry(configBuilder.getGlobalConfig());
        this.databaseMetaDataWrapper = new DatabaseMetaDataWrapper(dataSourceConfig.getConn(), dataSourceConfig.getSchemaName());
    }

    @Override
    public @NotNull List<TableInfo> queryTables() {
        try {
            boolean isInclude = !strategyConfig.getInclude().isEmpty();
            boolean isExclude = !strategyConfig.getExclude().isEmpty();
            //所有的表信息
            List<TableInfo> tableList = new ArrayList<>();
            List<DatabaseMetaDataWrapper.Table> tables = this.getTables();
            //需要反向生成或排除的表信息
            List<TableInfo> includeTableList = new ArrayList<>();
            List<TableInfo> excludeTableList = new ArrayList<>();
            tables.forEach(table -> {
                String tableName = table.getName();
                if (StringUtils.isNotBlank(tableName)) {
                    TableInfo tableInfo = new TableInfo(this.configBuilder, tableName);
                    tableInfo.setComment(table.getRemarks());
                    if (isInclude && strategyConfig.matchIncludeTable(tableName)) {
                        includeTableList.add(tableInfo);
                    } else if (isExclude && strategyConfig.matchExcludeTable(tableName)) {
                        excludeTableList.add(tableInfo);
                    }
                    tableList.add(tableInfo);
                }
            });
            filter(tableList, includeTableList, excludeTableList);
            // 性能优化,只处理需执行表字段 https://github.com/baomidou/mybatis-plus/issues/219
            tableList.forEach(this::convertTableFields);
            return tableList;
        } finally {
            // 数据库操作完成,释放连接对象
            databaseMetaDataWrapper.closeConnection();
        }
    }

    protected List<DatabaseMetaDataWrapper.Table> getTables() {
        // 是否跳过视图
        boolean skipView = strategyConfig.isSkipView();
        // 获取表过滤
        String tableNamePattern = null;
        if (strategyConfig.getLikeTable() != null) {
            tableNamePattern = strategyConfig.getLikeTable().getValue();
        }
        return databaseMetaDataWrapper.getTables(tableNamePattern, skipView ? new String[]{"TABLE"} : new String[]{"TABLE", "VIEW"});
    }

    protected void convertTableFields(@NotNull TableInfo tableInfo) {
        String tableName = tableInfo.getName();
        Map<String, DatabaseMetaDataWrapper.Column> columnsInfoMap = getColumnsInfo(tableName);
        Entity entity = strategyConfig.entity();
        columnsInfoMap.forEach((k, columnInfo) -> {
            String columnName = columnInfo.getName();
            TableField field = new TableField(this.configBuilder, columnName);
            // 处理ID
            if (columnInfo.isPrimaryKey()) {
                field.primaryKey(columnInfo.isAutoIncrement());
                tableInfo.setHavePrimaryKey(true);
                if (field.isKeyIdentityFlag() && entity.getIdType() != null) {
                    LOGGER.warn("当前表[{}]的主键为自增主键,会导致全局主键的ID类型设置失效!", tableName);
                }
            }
            field.setColumnName(columnName).setComment(columnInfo.getRemarks());
            String propertyName = entity.getNameConvert().propertyNameConvert(field);
            // 设置字段的元数据信息
            TableField.MetaInfo metaInfo = new TableField.MetaInfo(columnInfo, tableInfo);
            IColumnType columnType;
            ITypeConvertHandler typeConvertHandler = dataSourceConfig.getTypeConvertHandler();
            if (typeConvertHandler != null) {
                columnType = typeConvertHandler.convert(globalConfig, typeRegistry, metaInfo);
            } else {
                columnType = typeRegistry.getColumnType(metaInfo);
            }
            field.setPropertyName(propertyName, columnType);
            field.setMetaInfo(metaInfo);
            tableInfo.addField(field);
        });
        tableInfo.setIndexList(getIndex(tableName));
        tableInfo.processTable();
    }

    protected Map<String, DatabaseMetaDataWrapper.Column> getColumnsInfo(String tableName) {
        return databaseMetaDataWrapper.getColumnsInfo(tableName, true);
    }

    protected List<DatabaseMetaDataWrapper.Index> getIndex(String tableName) {
        return databaseMetaDataWrapper.getIndex(tableName);
    }
}

评论

登录后才可以发表评论
用户头像
liaosnet发表于 11个月前
考虑一下,是否提交到mybaits-plus代码中去。
GBase用户51883发表于 2个月前
继续努力
用户头像
levvel发表于 1个月前
受益匪浅!