diff --git a/CHANGELOG.md b/CHANGELOG.md index f50f7bb91..8223a282a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,7 @@ # 🚀Changelog ------------------------------------------------------------------------------------------------------------- -# 5.7.23 (2022-03-16) +# 5.7.23 (2022-03-17) ### 🐣新特性 * 【http 】 HttpRequest.form采用TableMap方式(issue#I4W427@Gitee) @@ -18,6 +18,7 @@ * 【core 】 FileAppender优化初始List大小(pr#2197@Github) * 【core 】 Base32增加pad支持(pr#2195@Github) * 【core 】 Dict增加setFields方法(pr#578@Gitee) +* 【db 】 新加db.meta的索引相关接口(pr#563@Gitee) * ### 🐞Bug修复 * 【core 】 修复ObjectUtil.hasNull传入null返回true的问题(pr#555@Gitee) diff --git a/hutool-db/src/main/java/cn/hutool/db/meta/Column.java b/hutool-db/src/main/java/cn/hutool/db/meta/Column.java index 7faf402c1..b472bc3ea 100644 --- a/hutool-db/src/main/java/cn/hutool/db/meta/Column.java +++ b/hutool-db/src/main/java/cn/hutool/db/meta/Column.java @@ -1,7 +1,6 @@ package cn.hutool.db.meta; import cn.hutool.core.util.BooleanUtil; -import cn.hutool.core.util.StrUtil; import cn.hutool.db.DbRuntimeException; import java.io.Serializable; @@ -93,7 +92,7 @@ public class Column implements Serializable, Cloneable { try { init(table, columnMetaRs); } catch (SQLException e) { - throw new DbRuntimeException(StrUtil.format("Get table [{}] meta info error!", tableName)); + throw new DbRuntimeException(e, "Get table [{}] meta info error!", tableName); } } // ----------------------------------------------------- Constructor end diff --git a/hutool-db/src/main/java/cn/hutool/db/meta/ColumnIndexInfo.java b/hutool-db/src/main/java/cn/hutool/db/meta/ColumnIndexInfo.java index 06404390d..d100cd208 100644 --- a/hutool-db/src/main/java/cn/hutool/db/meta/ColumnIndexInfo.java +++ b/hutool-db/src/main/java/cn/hutool/db/meta/ColumnIndexInfo.java @@ -1,24 +1,56 @@ package cn.hutool.db.meta; +import cn.hutool.db.DbRuntimeException; + import java.io.Serializable; +import java.sql.ResultSet; +import java.sql.SQLException; /** * 索引中的列信息 * * @author huzhongying + * @since 5.7.23 */ -public class ColumnIndexInfo implements Serializable, Cloneable{ +public class ColumnIndexInfo implements Serializable, Cloneable { + private static final long serialVersionUID = 1L; + + /** + * 根据DatabaseMetaData#getIndexInfo获取的{@link ResultSet}构建索引列信息 + * + * @param rs 结果集,通过DatabaseMetaData#getIndexInfo获取 + * @return ColumnIndexInfo + */ + public static ColumnIndexInfo create(ResultSet rs) { + try { + return new ColumnIndexInfo( + rs.getString("COLUMN_NAME"), + rs.getString("ASC_OR_DESC")); + } catch (SQLException e) { + throw new DbRuntimeException(e); + } + } /** * 列名 */ private String columnName; - /** * 列排序顺序,“A”: 升序,“D” : 降序,如果不支持排序顺序,可能为空 */ private String ascOrDesc; + /** + * 构造 + * + * @param columnName 索引列名 + * @param ascOrDesc 正序或反序,null表示无顺序表示 + */ + public ColumnIndexInfo(String columnName, String ascOrDesc) { + this.columnName = columnName; + this.ascOrDesc = ascOrDesc; + } + public String getColumnName() { return columnName; } @@ -34,4 +66,17 @@ public class ColumnIndexInfo implements Serializable, Cloneable{ public void setAscOrDesc(String ascOrDesc) { this.ascOrDesc = ascOrDesc; } + + @Override + public ColumnIndexInfo clone() throws CloneNotSupportedException { + return (ColumnIndexInfo) super.clone(); + } + + @Override + public String toString() { + return "ColumnIndexInfo{" + + "columnName='" + columnName + '\'' + + ", ascOrDesc='" + ascOrDesc + '\'' + + '}'; + } } diff --git a/hutool-db/src/main/java/cn/hutool/db/meta/IndexInfo.java b/hutool-db/src/main/java/cn/hutool/db/meta/IndexInfo.java index d3a3a142c..dd2cfb271 100644 --- a/hutool-db/src/main/java/cn/hutool/db/meta/IndexInfo.java +++ b/hutool-db/src/main/java/cn/hutool/db/meta/IndexInfo.java @@ -1,16 +1,21 @@ package cn.hutool.db.meta; +import cn.hutool.core.util.ObjectUtil; + import java.io.Serializable; import java.util.ArrayList; import java.util.List; +import java.util.Objects; /** - * 数据库表的索引信息 + * 数据库表的索引信息
+ * 如果时单列索引,只有一个{@link ColumnIndexInfo},联合索引则拥有多个{@link ColumnIndexInfo} * * @author huzhongying */ -public class IndexInfo implements Serializable, Cloneable{ +public class IndexInfo implements Serializable, Cloneable { + private static final long serialVersionUID = 1L; /** * 索引值是否可以不唯一 @@ -41,6 +46,24 @@ public class IndexInfo implements Serializable, Cloneable{ */ private List columnIndexInfoList; + /** + * 构造 + * + * @param nonUnique 索引值是否可以不唯一 + * @param indexName 索引名称 + * @param tableName 表名 + * @param schema table所在的schema + * @param catalog table所在的catalog + */ + public IndexInfo(boolean nonUnique, String indexName, String tableName, String schema, String catalog) { + this.nonUnique = nonUnique; + this.indexName = indexName; + this.tableName = tableName; + this.schema = schema; + this.catalog = catalog; + this.setColumnIndexInfoList(new ArrayList<>()); + } + public boolean isNonUnique() { return nonUnique; } @@ -89,21 +112,38 @@ public class IndexInfo implements Serializable, Cloneable{ this.columnIndexInfoList = columnIndexInfoList; } - /** - * - * @param nonUnique 索引值是否可以不唯一 - * @param indexName 索引名称 - * @param tableName 表名 - * @param schema table所在的schema - * @param catalog table所在的catalog - */ - public IndexInfo(boolean nonUnique, String indexName, String tableName, String schema, String catalog) { - this.nonUnique = nonUnique; - this.indexName = indexName; - this.tableName = tableName; - this.schema = schema; - this.catalog = catalog; - this.setColumnIndexInfoList(new ArrayList<>()); + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + IndexInfo indexInfo = (IndexInfo) o; + return ObjectUtil.equals(indexName, indexInfo.indexName) + && ObjectUtil.equals(tableName, indexInfo.tableName); } + @Override + public int hashCode() { + return Objects.hash(indexName, tableName); + } + + @Override + public IndexInfo clone() throws CloneNotSupportedException { + return (IndexInfo) super.clone(); + } + + @Override + public String toString() { + return "IndexInfo{" + + "nonUnique=" + nonUnique + + ", indexName='" + indexName + '\'' + + ", tableName='" + tableName + '\'' + + ", schema='" + schema + '\'' + + ", catalog='" + catalog + '\'' + + ", columnIndexInfoList=" + columnIndexInfoList + + '}'; + } } diff --git a/hutool-db/src/main/java/cn/hutool/db/meta/MetaUtil.java b/hutool-db/src/main/java/cn/hutool/db/meta/MetaUtil.java index 85c3e85a3..bb151db76 100644 --- a/hutool-db/src/main/java/cn/hutool/db/meta/MetaUtil.java +++ b/hutool-db/src/main/java/cn/hutool/db/meta/MetaUtil.java @@ -2,7 +2,6 @@ package cn.hutool.db.meta; import cn.hutool.core.collection.ListUtil; import cn.hutool.core.convert.Convert; -import cn.hutool.core.map.MapUtil; import cn.hutool.core.util.StrUtil; import cn.hutool.db.DbRuntimeException; import cn.hutool.db.DbUtil; @@ -83,7 +82,7 @@ public class MetaUtil { conn = ds.getConnection(); // catalog和schema获取失败默认使用null代替 - String catalog = getCataLog(conn); + String catalog = getCatalog(conn); if (null == schema) { schema = getSchema(conn); } @@ -144,7 +143,7 @@ public class MetaUtil { conn = ds.getConnection(); // catalog和schema获取失败默认使用null代替 - String catalog = getCataLog(conn); + String catalog = getCatalog(conn); String schema = getSchema(conn); final DatabaseMetaData metaData = conn.getMetaData(); @@ -202,8 +201,8 @@ public class MetaUtil { * * @param ds 数据源 * @param tableName 表名 - * @param catalog catalog name,{@code null}表示自动获取,见:{@link #getCataLog(Connection)} - * @param schema a schema name pattern,{@code null}表示自动获取,见:{@link #getSchema(Connection)} + * @param catalog catalog name,{@code null}表示自动获取,见:{@link #getCatalog(Connection)} + * @param schema a schema name pattern,{@code null}表示自动获取,见:{@link #getSchema(Connection)} * @return Table对象 * @since 5.7.22 */ @@ -214,11 +213,11 @@ public class MetaUtil { conn = ds.getConnection(); // catalog和schema获取失败默认使用null代替 - if(null == catalog){ - catalog = getCataLog(conn); + if (null == catalog) { + catalog = getCatalog(conn); } table.setCatalog(catalog); - if(null == schema){ + if (null == schema) { schema = getSchema(conn); } table.setSchema(schema); @@ -252,33 +251,30 @@ public class MetaUtil { } } - - // 获得索引信息 - - try (ResultSet rs = metaData.getIndexInfo(catalog, schema, tableName, false,false)) { - Map indexInfoMap = MapUtil.createMap(LinkedHashMap.class); + // 获得索引信息(since 5.7.23) + try (ResultSet rs = metaData.getIndexInfo(catalog, schema, tableName, false, false)) { + final Map indexInfoMap = new LinkedHashMap<>(); if (null != rs) { while (rs.next()) { //排除tableIndexStatistic类型索引 - if (rs.getShort("TYPE") != 0) { - String indexName = rs.getString("INDEX_NAME"); - String key = StrUtil.join("&", tableName, indexName); - IndexInfo indexInfo = indexInfoMap.getOrDefault(key - , new IndexInfo(rs.getBoolean("NON_UNIQUE"),indexName,tableName,schema,catalog)); - ColumnIndexInfo columnIndexInfo = new ColumnIndexInfo(); - columnIndexInfo.setColumnName(rs.getString("COLUMN_NAME")); - columnIndexInfo.setAscOrDesc(rs.getString("ASC_OR_DESC")); - indexInfo.getColumnIndexInfoList().add(columnIndexInfo); - if (!indexInfoMap.containsKey(key)) { - indexInfoMap.put(key,indexInfo); - } - + if (0 == rs.getShort("TYPE")) { + continue; } + + final String indexName = rs.getString("INDEX_NAME"); + final String key = StrUtil.join("&", tableName, indexName); + // 联合索引情况下一个索引会有多个列,此处须组合索引列到一个索引信息对象下 + IndexInfo indexInfo = indexInfoMap.get(key); + if (null == indexInfo) { + indexInfo = new IndexInfo(rs.getBoolean("NON_UNIQUE"), indexName, tableName, schema, catalog); + indexInfoMap.put(key, indexInfo); + } + indexInfo.getColumnIndexInfoList().add(ColumnIndexInfo.create(rs)); } } table.setIndexInfoList(ListUtil.toList(indexInfoMap.values())); } - } catch (SQLException e) { + } catch (SQLException e) { throw new DbRuntimeException("Get columns error!", e); } finally { DbUtil.close(conn); @@ -293,8 +289,21 @@ public class MetaUtil { * @param conn {@link Connection} 数据库连接,{@code null}时返回null * @return catalog,获取失败返回{@code null} * @since 4.6.0 + * @deprecated 拼写错误,请使用{@link #getCatalog(Connection)} */ + @Deprecated public static String getCataLog(Connection conn) { + return getCatalog(conn); + } + + /** + * 获取catalog,获取失败返回{@code null} + * + * @param conn {@link Connection} 数据库连接,{@code null}时返回null + * @return catalog,获取失败返回{@code null} + * @since 5.7.23 + */ + public static String getCatalog(Connection conn) { if (null == conn) { return null; } diff --git a/hutool-db/src/main/java/cn/hutool/db/meta/Table.java b/hutool-db/src/main/java/cn/hutool/db/meta/Table.java index ae7b7e09b..7046b1284 100644 --- a/hutool-db/src/main/java/cn/hutool/db/meta/Table.java +++ b/hutool-db/src/main/java/cn/hutool/db/meta/Table.java @@ -1,7 +1,12 @@ package cn.hutool.db.meta; import java.io.Serializable; -import java.util.*; +import java.util.Collection; +import java.util.LinkedHashMap; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; /** * 数据库表信息 @@ -31,11 +36,13 @@ public class Table implements Serializable, Cloneable { * 主键字段名列表 */ private Set pkNames = new LinkedHashSet<>(); - /** * 索引信息 */ private List indexInfoList; + /** + * 列映射,列名-列对象 + */ private final Map columns = new LinkedHashMap<>(); public static Table create(String tableName) { @@ -154,7 +161,7 @@ public class Table implements Serializable, Cloneable { * @return 是否为主键 * @since 5.4.3 */ - public boolean isPk(String columnName){ + public boolean isPk(String columnName) { return getPkNames().contains(columnName); } @@ -213,13 +220,26 @@ public class Table implements Serializable, Cloneable { /** * 获取索引信息 + * * @return 索引信息 + * @since 5.7.23 */ public List getIndexInfoList() { return indexInfoList; } + /** + * 设置索引信息 + * + * @param indexInfoList 索引信息列表 + * @since 5.7.23 + */ public void setIndexInfoList(List indexInfoList) { this.indexInfoList = indexInfoList; } + + @Override + public Table clone() throws CloneNotSupportedException { + return (Table) super.clone(); + } } diff --git a/hutool-db/src/main/java/cn/hutool/db/meta/TableType.java b/hutool-db/src/main/java/cn/hutool/db/meta/TableType.java index 7c65bda4d..c22c084bc 100644 --- a/hutool-db/src/main/java/cn/hutool/db/meta/TableType.java +++ b/hutool-db/src/main/java/cn/hutool/db/meta/TableType.java @@ -2,35 +2,38 @@ package cn.hutool.db.meta; /** * 元信息中表的类型 - * @author Looly * + * @author Looly */ public enum TableType { TABLE("TABLE"), VIEW("VIEW"), - SYSTEM_TABLE ("SYSTEM TABLE"), + SYSTEM_TABLE("SYSTEM TABLE"), GLOBAL_TEMPORARY("GLOBAL TEMPORARY"), LOCAL_TEMPORARY("LOCAL TEMPORARY"), ALIAS("ALIAS"), SYNONYM("SYNONYM"); - + private final String value; - + /** * 构造 + * * @param value 值 */ - TableType(String value){ + TableType(String value) { this.value = value; } + /** * 获取值 + * * @return 值 */ - public String value(){ + public String value() { return this.value; } - + @Override public String toString() { return this.value(); diff --git a/hutool-db/src/main/java/cn/hutool/db/sql/Direction.java b/hutool-db/src/main/java/cn/hutool/db/sql/Direction.java index 9e573093e..d8f1ee30c 100644 --- a/hutool-db/src/main/java/cn/hutool/db/sql/Direction.java +++ b/hutool-db/src/main/java/cn/hutool/db/sql/Direction.java @@ -4,23 +4,39 @@ import cn.hutool.core.util.StrUtil; /** * 排序方式(升序或者降序) - * @author Looly * + * @author Looly */ -public enum Direction{ - /** 升序 */ - ASC, - /** 降序 */ - DESC; - +public enum Direction { /** - * 根据字符串值返回对应{@link Direction}值 - * + * 升序 + */ + ASC, + /** + * 降序 + */ + DESC; + + /** + * 根据字符串值返回对应Direction值 + * * @param value 排序方式字符串,只能是 ASC或DESC - * @return {@link Direction} + * @return Direction,{@code null}表示提供的value为空 * @throws IllegalArgumentException in case the given value cannot be parsed into an enum value. */ - public static Direction fromString(String value) throws IllegalArgumentException{ + public static Direction fromString(String value) throws IllegalArgumentException { + if (StrUtil.isEmpty(value)) { + return null; + } + + // 兼容元数据中ASC和DESC表示 + if (1 == value.length()) { + if ("A".equalsIgnoreCase(value)) { + return ASC; + } else if ("D".equalsIgnoreCase(value)) { + return DESC; + } + } try { return Direction.valueOf(value.toUpperCase()); diff --git a/hutool-db/src/test/java/cn/hutool/db/meta/MetaUtilTest.java b/hutool-db/src/test/java/cn/hutool/db/meta/MetaUtilTest.java index 4438c2a87..0abd88676 100644 --- a/hutool-db/src/test/java/cn/hutool/db/meta/MetaUtilTest.java +++ b/hutool-db/src/test/java/cn/hutool/db/meta/MetaUtilTest.java @@ -1,15 +1,13 @@ package cn.hutool.db.meta; -import java.util.List; - -import javax.sql.DataSource; - -import org.junit.Assert; -import org.junit.Test; - import cn.hutool.core.collection.CollectionUtil; import cn.hutool.core.util.StrUtil; import cn.hutool.db.ds.DSFactory; +import org.junit.Assert; +import org.junit.Test; + +import javax.sql.DataSource; +import java.util.List; /** * 元数据信息单元测试