写点什么

Java 从建表语句中提取索引信息, 索引名称, 复合索引包含字段, 索引类别 (普通索引 / 主键索引 / 唯一索引 / 全文索引 / 空间索引) 解决方案

用户头像
张音乐
关注
发布于: 1 小时前
Java从建表语句中提取索引信息, 索引名称,复合索引包含字段,索引类别(普通索引/主键索引/唯一索引/全文索引/空间索引)解决方案

查阅了多方面资料, 对比并尝试了以下几种方案, 我个人在项目中是需要最后一种才能满足需求, 现在列举并说明以下.

一.方案一 

DatabaseMetaData , 这种方式代码如下, 这种方式获取的索引类型其实是如下几种

* tableIndexStatistic - 此标识与表的索引描述一起返回的表统计信息

* tableIndexClustered - 此为集群索引

* tableIndexHashed - 此为散列索引

* tableIndexOther - 此为某种其他样式的索引


因为我也没有具体创建过这几种索引,所以也不认识. 但是很明显不符合我们的需求. 

代码如下

    /**     * 获得一个表的索引信息     * getIndexInfo     * catalog : 类别名称,因为存储在此数据库中,所以它必须匹配类别名称。该参数为 “” 则检索没有类别的描述,为 null 则表示该类别名称不应用于缩小搜索范围     * schema : 模式名称,因为存储在此数据库中,所以它必须匹配模式名称。该参数为 “” 则检索那些没有模式的描述,为 null 则表示该模式名称不应用于缩小搜索范围     * table : 表名称,因为存储在此数据库中,所以它必须匹配表名称     * unique : 该参数为 true 时,仅返回惟一值的索引;该参数为 false 时,返回所有索引,不管它们是否惟一     * approximate : 该参数为 true 时,允许结果是接近的数据值或这些数据值以外的值;该参数为 false 时,要求结果是精确结果     */    public void queryIndexInfo(String dbName, String tableName, DatabaseMetaData metaData) {        ResultSet rs = null;        try {            rs = metaData.getIndexInfo(null, dbName, tableName, false, true);            while (rs.next()) {                String ascOrDesc = rs.getString("ASC_OR_DESC");         // 列排序顺序: 升序还是降序                int cardinality = rs.getInt("CARDINALITY");             // 基数                short ordinalPosition = rs.getShort("ORDINAL_POSITION");// 在索引列顺序号                boolean nonUnique = rs.getBoolean("NON_UNIQUE");        // 非唯一索引(Can index values be non-unique. false when TYPE is  tableIndexStatistic   )                String indexQualifier = rs.getString("INDEX_QUALIFIER");// 索引目录(可能为空)                String indexName = rs.getString("INDEX_NAME");          // 索引的名称                short indexType = rs.getShort("TYPE");          // 索引类型                String columnName = rs.getString("COLUMN_NAME");            }        } catch (SQLException e) {            log.error(e.getMessage(), e);        } finally {            //         }    }
复制代码

二.方案二

自定义查询语句从 information_schema.`COLUMNS` 中获取索引信息, 但是获取的索只有三种类型

PRI:  主键约束;

UNI:  唯一约束;

MUL: 可以重复。

selecttable_name, column_name, column_keyfrominformation_schema.`COLUMNS`where  table_schema = 'proxy'  and table_name = 'dim_nor'
复制代码


 很明显也是不符合需求的

三.方案三

这种方式也是通过 SQL 来进行查询.

show index from dim_prishow key from dim_pri
复制代码



这种方式也没能达到要求.

四.方案四

使用 sql 解析器来解析建表语句

这里同学有空的话可以找找有没有成熟的方案, 例如 DRUID 和 jsqlparser

这里因为我只需要解析建表语句, 所以我还是自己写了一下. 多余的不说了, 上代码

定义两个基本对象

package com.biubiu.dms.core.model; import lombok.Data; import java.util.List; /** * @author :张音乐 * @date :Created in 2021/8/13 下午12:56 * @description:索引信息 * @email: zhangyule1993@sina.com * @version: */@Datapublic class QueryKey {    private String indexName;    private String indexType;    private List<IndexColumn> indexColumns;}
复制代码


package com.biubiu.dms.core.model; import lombok.Data; /** * @author :张音乐 * @date :Created in 2021/8/13 下午12:57 * @description:索引包含列 * @email: zhangyule1993@sina.com * @version: */@Datapublic class IndexColumn {    private String columnName;    private String length;    private String order;}
复制代码

具体解析方法, 这里最好从数据库获取建表语句, 因为 mysql 会给我们格式化一下, 这样获取到的是标准的建表语句.

     public List<QueryKey> getKeyInfo(String tableName) throws Exception {        List<QueryKey> resList = new ArrayList<>();        String sql = "SHOW CREATE TABLE `" + tableName + "`";        // 执行查询 ..省略, 毕竟每个人不一样        // 假设你是用jdbc来查询, 那么这里ResultSet 中获取 "Create Table" 字段.        String text = rs.getString("Create Table").toString().toLowerCase();        String temp = org.apache.commons.lang3.StringUtils.substringAfter(text, "(");        String temp2 = org.apache.commons.lang3.StringUtils.substringBeforeLast(temp, ")");        String [] arr = org.apache.commons.lang3.StringUtils.split(temp2, "\n");        List<String> keyTextList = Arrays.stream(arr).filter(p -> p.contains("key") || p.contains("index")).collect(Collectors.toList());        for(int i = 0; i < keyTextList.size(); i++) {            QueryKey queryKey = new QueryKey();            String item = keyTextList.get(i);            // 获取 索引类型            String type = getKeyType(item);            queryKey.setIndexType(type);            // 获取索引名称            String indexName = getKeyName(item, type);            queryKey.setIndexName(indexName);            // 获取索引字段            String fieldInfoAfter = org.apache.commons.lang3.StringUtils.substringAfter(item, "(");            String fieldInfo = org.apache.commons.lang3.StringUtils.substringBeforeLast(fieldInfoAfter, ")");            String[] columns = org.apache.commons.lang3.StringUtils.split(fieldInfo, ",");            List<IndexColumn> columnsList = getKeyColumns(columns);            queryKey.setIndexColumns(columnsList);            resList.add(queryKey);        }        return resList;    }     private List<IndexColumn> getKeyColumns(String[] columns) {        List<IndexColumn> columnsList = Arrays.stream(columns).map(p -> {            // `id`            // `name`(2) DESC            IndexColumn indexColumn = new IndexColumn();            String columnName = org.apache.commons.lang3.StringUtils.substringBetween(p, "`", "`");            indexColumn.setColumnName(columnName);            String regEx="[^0-9]";            Pattern pattern = Pattern.compile(regEx);            Matcher m = pattern.matcher(p);            // 前缀限制长度            String length = m.replaceAll("").trim();            indexColumn.setLength(length);            String order = p.contains("desc") ? "DESC" : "ASC";            indexColumn.setOrder(order);            return indexColumn;        }).collect(Collectors.toList());        return columnsList;    }     private String getKeyName(String item, String type) {        String indexName = "";        if(type.equals("Primary")) {            // 主键索引一定是 PRIMARY, 但是在建表语句中是省略的            indexName = "PRIMARY";        } else {            String itemAfter = org.apache.commons.lang3.StringUtils.substringAfter(item, "key");            indexName = org.apache.commons.lang3.StringUtils.substringBefore(itemAfter, "(").replaceAll("`", "").trim();        }        return indexName;    }     private String getKeyType(String item) {        String type = "Normal";        String keyType = org.apache.commons.lang3.StringUtils.substringBefore(item, "key");        if(org.apache.commons.lang3.StringUtils.isNotBlank(keyType)) {            if(keyType.trim().equals("primary") ) {                type = "Primary";            }            if(keyType.trim().equals("unique")) {                type = "Unique";            }            if(keyType.trim().equals("fullText")) {                type = "FullText";            }            if(keyType.trim().equals("spatial")) {                type = "Spatial";            }        }        return type;    }
复制代码


格式如下:

[    // 例如 Primary Key `id`    {        "indexName":"PRIMARY",        "indexType":"Primary",        "indexColumns":[            {                "columnName":"id",                "length":"",                "order":"ASC"            }        ]    },    // 例如 Unique Key (`id`, `name`(2) DESC )    {        "indexName":"idx_ss",        "indexType":"Unique",        "indexColumns":[            {                "columnName":"id",                "length":"",                "order":"ASC"            },            {                "columnName":"name",                "length":"2",                "order":"DESC"            }        ]    }]
复制代码


用这种方式的化在建表的时候就需要规范以下建表规则了, 但是应该可以覆盖大部分了.


发布于: 1 小时前阅读数: 2
用户头像

张音乐

关注

求你关注我,别不识抬举.别逼我跪下来求你. 2021.03.28 加入

还未添加个人简介

评论

发布
暂无评论
Java从建表语句中提取索引信息, 索引名称,复合索引包含字段,索引类别(普通索引/主键索引/唯一索引/全文索引/空间索引)解决方案