All Downloads are FREE. Search and download functionalities are using the official Maven repository.

cn.hutool.db.meta.MetaUtil Maven / Gradle / Ivy

Go to download

Hutool是一个小而全的Java工具类库,通过静态方法封装,降低相关API的学习成本,提高工作效率,使Java拥有函数式语言般的优雅,让Java语言也可以“甜甜的”。

There is a newer version: 5.8.34
Show newest version
package cn.hutool.db.meta;

import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.db.DbRuntimeException;
import cn.hutool.db.DbUtil;
import cn.hutool.db.Entity;

import javax.sql.DataSource;
import java.sql.*;
import java.util.*;

/**
 * 数据库元数据信息工具类
 *
 * 

* 需要注意的是,此工具类在某些数据库(比如Oracle)下无效,此时需要手动在数据库配置中增加: *

 *  remarks = true
 *  useInformationSchema = true
 * 
* * @author looly */ public class MetaUtil { /** * 获得所有表名 * * @param ds 数据源 * @return 表名列表 */ public static List getTables(DataSource ds) { return getTables(ds, TableType.TABLE); } /** * 获得所有表名 * * @param ds 数据源 * @param types 表类型 * @return 表名列表 */ public static List getTables(DataSource ds, TableType... types) { return getTables(ds, null, null, types); } /** * 获得所有表名 * * @param ds 数据源 * @param schema 表数据库名,对于Oracle为用户名 * @param types 表类型 * @return 表名列表 * @since 3.3.1 */ public static List getTables(DataSource ds, String schema, TableType... types) { return getTables(ds, schema, null, types); } /** * 获得所有表名 * * @param ds 数据源 * @param schema 表数据库名,对于Oracle为用户名 * @param tableName 表名 * @param types 表类型 * @return 表名列表 * @since 3.3.1 */ public static List getTables(DataSource ds, String schema, String tableName, TableType... types) { final List tables = new ArrayList<>(); Connection conn = null; try { conn = ds.getConnection(); // catalog和schema获取失败默认使用null代替 final String catalog = getCatalog(conn); if (null == schema) { schema = getSchema(conn); } final DatabaseMetaData metaData = conn.getMetaData(); try (final ResultSet rs = metaData.getTables(catalog, schema, tableName, Convert.toStrArray(types))) { if (null != rs) { String table; while (rs.next()) { table = rs.getString("TABLE_NAME"); if (StrUtil.isNotBlank(table)) { tables.add(table); } } } } } catch (Exception e) { throw new DbRuntimeException("Get tables error!", e); } finally { DbUtil.close(conn); } return tables; } /** * 获得结果集的所有列名 * * @param rs 结果集 * @return 列名数组 * @throws DbRuntimeException SQL执行异常 */ public static String[] getColumnNames(ResultSet rs) throws DbRuntimeException { try { final ResultSetMetaData rsmd = rs.getMetaData(); final int columnCount = rsmd.getColumnCount(); final String[] labelNames = new String[columnCount]; for (int i = 0; i < labelNames.length; i++) { labelNames[i] = rsmd.getColumnLabel(i + 1); } return labelNames; } catch (Exception e) { throw new DbRuntimeException("Get colunms error!", e); } } /** * 获得表的所有列名 * * @param ds 数据源 * @param tableName 表名 * @return 列数组 * @throws DbRuntimeException SQL执行异常 */ public static String[] getColumnNames(DataSource ds, String tableName) { final List columnNames = new ArrayList<>(); Connection conn = null; try { conn = ds.getConnection(); // catalog和schema获取失败默认使用null代替 final String catalog = getCatalog(conn); final String schema = getSchema(conn); final DatabaseMetaData metaData = conn.getMetaData(); try (final ResultSet rs = metaData.getColumns(catalog, schema, tableName, null)) { if (null != rs) { while (rs.next()) { columnNames.add(rs.getString("COLUMN_NAME")); } } } return columnNames.toArray(new String[0]); } catch (Exception e) { throw new DbRuntimeException("Get columns error!", e); } finally { DbUtil.close(conn); } } /** * 创建带有字段限制的Entity对象
* 此方法读取数据库中对应表的字段列表,加入到Entity中,当Entity被设置内容时,会忽略对应表字段外的所有KEY * * @param ds 数据源 * @param tableName 表名 * @return Entity对象 */ public static Entity createLimitedEntity(DataSource ds, String tableName) { final String[] columnNames = getColumnNames(ds, tableName); return Entity.create(tableName).setFieldNames(columnNames); } /** * 获得表的元信息
* 注意如果需要获取注释,某些数据库如MySQL,需要在配置中添加: *
	 *     remarks = true
	 *     useInformationSchema = true
	 * 
* * @param ds 数据源 * @param tableName 表名 * @return Table对象 */ public static Table getTableMeta(DataSource ds, String tableName) { return getTableMeta(ds, null, null, tableName); } /** * 获得表的元信息
* 注意如果需要获取注释,某些数据库如MySQL,需要在配置中添加: *
	 *     remarks = true
	 *     useInformationSchema = true
	 * 
* * @param ds 数据源 * @param tableName 表名 * @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 */ public static Table getTableMeta(DataSource ds, String catalog, String schema, String tableName) { Connection conn = null; try { conn = ds.getConnection(); return getTableMeta(conn, catalog, schema, tableName); } catch (final SQLException e){ throw new DbRuntimeException(e); } finally { IoUtil.close(conn); } } /** * 获得表的元信息
* 注意如果需要获取注释,某些数据库如MySQL,需要在配置中添加: *
	 *     remarks = true
	 *     useInformationSchema = true
	 * 
* * @param conn 数据库连接对象,使用结束后不会关闭。 * @param tableName 表名 * @param catalog catalog name,{@code null}表示自动获取,见:{@link #getCatalog(Connection)} * @param schema a schema name pattern,{@code null}表示自动获取,见:{@link #getSchema(Connection)} * @return Table对象 * @since 5.8.28 */ public static Table getTableMeta(final Connection conn, String catalog, String schema, final String tableName) { final Table table = Table.create(tableName); // catalog和schema获取失败默认使用null代替 if (null == catalog) { catalog = getCatalog(conn); } table.setCatalog(catalog); if (null == schema) { schema = getSchema(conn); } table.setSchema(schema); final DatabaseMetaData metaData = getMetaData(conn); // 获取原始表名 final String pureTableName = unWrapIfOracle(metaData, tableName); // 获得表元数据(表注释) table.setComment(getRemarks(metaData, catalog, schema, pureTableName)); // 获得主键 table.setPkNames(getPrimaryKeys(metaData, catalog, schema, pureTableName)); // 获得列 fetchColumns(metaData, catalog, schema, table); // 获得索引信息(since 5.7.23) final Map indexInfoMap = getIndexInfo(metaData, catalog, schema, tableName); table.setIndexInfoList(ListUtil.toList(indexInfoMap.values())); return table; } /** * 获取catalog,获取失败返回{@code null} * * @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; } try { return conn.getCatalog(); } catch (SQLException e) { // ignore } return null; } /** * 获取schema,获取失败返回{@code null} * * @param conn {@link Connection} 数据库连接,{@code null}时返回null * @return schema,获取失败返回{@code null} * @since 4.6.0 */ public static String getSchema(Connection conn) { if (null == conn) { return null; } try { return conn.getSchema(); } catch (SQLException e) { // ignore } return null; } /** * 获取数据库连接的元数据信息。 * * @param conn 数据库连接对象。如果连接为null,则返回null。 * @return DatabaseMetaData 数据库元数据对象,如果获取失败或连接为null,则返回null。 * @since 5.8.28 */ public static DatabaseMetaData getMetaData(final Connection conn) { if (null == conn) { return null; } try { return conn.getMetaData(); } catch (final SQLException e) { // ignore } return null; } /** * 获取指定表的备注信息。 * * @param metaData 数据库元数据,用于查询表信息。 * @param catalog 目录名称,用于指定查询的数据库(可为{@code null},表示任意目录)。 * @param schema 方案名称,用于指定表所属的schema(可为{@code null},表示任意schema)。 * @param tableName 表名称,指定要查询备注信息的表。 * @return 表的备注信息。未找到指定的表或查询成功但无结果,则返回null。 * @since 5.8.28 */ public static String getRemarks(final DatabaseMetaData metaData, final String catalog, final String schema, String tableName) { // issue#I9BANE Oracle中特殊表名需要解包 tableName = unWrapIfOracle(metaData, tableName); try (final ResultSet rs = metaData.getTables(catalog, schema, tableName, new String[]{TableType.TABLE.value()})) { if (null != rs) { if (rs.next()) { return rs.getString("REMARKS"); } } } catch (final SQLException e) { throw new DbRuntimeException(e); } // 未找到指定的表或查询成功但无结果 return null; } /** * 获取指定表的主键列名列表。 * * @param metaData 数据库元数据,用于查询主键信息。 * @param catalog 数据库目录,用于限定查询范围。 * @param schema 数据库模式,用于限定查询范围。 * @param tableName 表名,指定要查询主键的表。 * @return 主键列名的列表。如果表没有主键,则返回空列表。 * @throws DbRuntimeException 如果查询过程中发生SQLException,将抛出DbRuntimeException。 * @since 5.8.28 */ public static Set getPrimaryKeys(final DatabaseMetaData metaData, final String catalog, final String schema, String tableName) { // issue#I9BANE Oracle中特殊表名需要解包 tableName = unWrapIfOracle(metaData, tableName); // 初始化主键列表 Set primaryKeys = null; try (final ResultSet rs = metaData.getPrimaryKeys(catalog, schema, tableName)) { // 如果结果集不为空,遍历结果集获取主键列名 if (null != rs) { primaryKeys = new LinkedHashSet<>(rs.getFetchSize(), 1); while (rs.next()) { primaryKeys.add(rs.getString("COLUMN_NAME")); } } } catch (final SQLException e) { // 将SQLException转换为自定义的DbException抛出 throw new DbRuntimeException(e); } return primaryKeys; } /** * 获取指定表的索引信息。 * * @param metaData 数据库元数据,用于查询索引信息。 * @param catalog 数据库目录,用于限定查询范围。 * @param schema 数据库模式,用于限定查询范围。 * @param tableName 需要查询索引信息的表名。 * @return 返回一个映射,其中包含表的索引信息。键是表名和索引名的组合,值是索引信息对象。 * @since 5.8.28 */ public static Map getIndexInfo(final DatabaseMetaData metaData, final String catalog, final String schema, final String tableName) { final Map indexInfoMap = new LinkedHashMap<>(); try (final ResultSet rs = metaData.getIndexInfo(catalog, schema, tableName, false, false)) { if (null != rs) { while (rs.next()) { //排除统计(tableIndexStatistic)类型索引 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)); } } } catch (final SQLException e) { throw new DbRuntimeException(e); } return indexInfoMap; } /** * 判断当前数据库是否为Oracle。 * * @param metaData 数据库元数据,用于获取数据库产品名称。 * @return 返回true表示当前数据库是Oracle,否则返回false。 * @throws DbRuntimeException 如果获取数据库产品名称时发生SQLException,将抛出DbRuntimeException。 * @since 5.8.28 */ public static boolean isOracle(final DatabaseMetaData metaData) throws DbRuntimeException { try { return StrUtil.equalsIgnoreCase("Oracle", metaData.getDatabaseProductName()); } catch (final SQLException e) { throw new DbRuntimeException(e); } } /** * 如果是在Oracle数据库中并且表名被双引号包裹,则移除这些引号。 * * @param metaData 数据库元数据,用于判断是否为Oracle数据库。 * @param tableName 待处理的表名,可能被双引号包裹。 * @return 处理后的表名,如果原表名被双引号包裹且是Oracle数据库,则返回去除了双引号的表名;否则返回原表名。 */ private static String unWrapIfOracle(final DatabaseMetaData metaData, String tableName) { final char wrapChar = '"'; // 判断表名是否被双引号包裹且当前数据库为Oracle,如果是,则移除双引号 if (StrUtil.isWrap(tableName, wrapChar) && isOracle(metaData)) { tableName = StrUtil.unWrap(tableName, wrapChar); } return tableName; } /** * 从数据库元数据中获取指定表的列信息。 * * @param metaData 数据库元数据,用于查询列信息。 * @param catalog 数据库目录,用于过滤列信息。 * @param schema 数据库模式,用于过滤列信息。 * @param table 表对象,用于存储获取到的列信息。 */ private static void fetchColumns(final DatabaseMetaData metaData, final String catalog, final String schema, final Table table) { // issue#I9BANE Oracle中特殊表名需要解包 final String tableName = unWrapIfOracle(metaData, table.getTableName()); // 获得列 try (final ResultSet rs = metaData.getColumns(catalog, schema, tableName, null)) { if (null != rs) { while (rs.next()) { table.setColumn(Column.create(table, rs)); } } } catch (final SQLException e) { throw new DbRuntimeException(e); } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy