jdbc元数据DataBaseMetaData查询数据库表信息详解

该代码实现了一个Java服务,通过JDBC连接获取指定数据库的表信息和表字段信息。它首先从请求数据中解析数据库连接信息,然后建立数据库连接并获取元数据。接着,它遍历元数据以获取表列表、表详细信息以及每个表的字段信息。服务还包含了处理异常、关闭连接的功能,并提供了实体类与数据库字段类型的比较方法。

使用jdbc驱动的元数据metaData获取指定数据库的表信息和表字段信息。

测试请求:http://localhost:30001/api/tableInfoQuery/queryTableInfos

测试数据:{“dataSourceUrl”: “jdbc:mysql://192.168.51.1:3306/yusp_plus_real_xs?useUnicode=true&characterEncoding=utf-8&allowMultiQueries=true”,“userName”: “root”,“passWord”: “123456”}

测试时请更改数据库链接配置信息。

下面代码不全,需要补充下contrller入口调用类、TableInfoQueyVO实体对象。这里只是写了实现方法

package cn.com.yusys.yusp.base.data.service.impl;

import cn.com.yusys.yusp.base.data.domain.vo.TableInfoQueyVO;
import cn.com.yusys.yusp.base.data.service.TableInfoQueryService;
import cn.com.yusys.yusp.commons.util.StringUtils;
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.lang.reflect.Field;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.util.*;

/**
 * @DATE 2022/4/24 10:04
 * @USER luofeng
 * @NAME TableInfoQueryServiceImpl
 * @VERSION 1.0.0_V
 * @DESC
 */
@Slf4j
@Service("tableInfoQueryService")
public class TableInfoQueryServiceImpl implements TableInfoQueryService {
    @Override
    public List<TableInfoQueyVO> getTableFieldInfo(String dataInfo) throws Exception {

        Map<String,String> dataSourceInfos = (Map<String, String>) JSON.parse(dataInfo);
        String dataSourceUrl = dataSourceInfos.get("dataSourceUrl");
        if (StringUtils.isBlank(dataSourceUrl)){
            throw new Exception("数据源信息为空!");
        }
        String userName = dataSourceInfos.get("userName");
        if (StringUtils.isBlank(userName)){
            throw new Exception("该用户信息为空!");
        }
        String passWord = dataSourceInfos.get("passWord");
        if (StringUtils.isBlank(passWord)){
            throw new Exception("该用户密码为空!");
        }
        String tableName = dataSourceInfos.get("tableName");
        if (StringUtils.isBlank(tableName)){
            throw new Exception("查询表名不能为空!");
        }
        Connection conn = getDataSourceConn(dataSourceUrl,userName,passWord);
        log.info("-------数据源初始化结束------");
        //获取链接元数据信息。
        DatabaseMetaData metaData = conn.getMetaData();

        List<TableInfoQueyVO> tableFields = this.getTableFields(metaData, tableName,dataSourceUrl,userName);
        return tableFields;
    }

    @Override
    public List<Map<String, String>> getTableListInfo(String dataSourceInfo) throws Exception {

        Map<String,String> dataSourceInfos = (Map<String, String>) JSON.parse(dataSourceInfo);
        String dataSourceUrl = dataSourceInfos.get("dataSourceUrl");
        if (StringUtils.isBlank(dataSourceUrl)){
            throw new Exception("数据源信息为空!");
        }
        String userName = dataSourceInfos.get("userName");
        if (StringUtils.isBlank(userName)){
            throw new Exception("该用户信息为空!");
        }
        String passWord = dataSourceInfos.get("passWord");
        if (StringUtils.isBlank(passWord)){
            throw new Exception("该用户密码为空!");
        }

        log.info("开始查询数据源{}-{}-{},信息",dataSourceUrl,userName,passWord);

        Connection conn = getDataSourceConn(dataSourceUrl,userName,passWord);
        log.info("-------数据源初始化结束------");
        //获取链接元数据信息。
        DatabaseMetaData metaData = conn.getMetaData();

        List<Map<String, String>> tableList = this.getTableInfoList(metaData,dataSourceUrl,userName);

        closeConnection(conn);

        return tableList;
    }

    /**
     * 根据数据源 获取改数据源下说有的表结构信息。
     *
     * @param dataSourceInfo
     * @return
     */
    @Override
    public List<Map<String, Object>> getTableInfos(String dataSourceInfo) throws Exception{

        Map<String,String> dataSourceInfos = (Map<String, String>) JSON.parse(dataSourceInfo);
        String dataSourceUrl = dataSourceInfos.get("dataSourceUrl");
        if (StringUtils.isBlank(dataSourceUrl)){
            throw new Exception("数据源信息为空!");
        }
        String userName = dataSourceInfos.get("userName");
        if (StringUtils.isBlank(userName)){
            throw new Exception("该用户信息为空!");
        }
        String passWord = dataSourceInfos.get("passWord");
        if (StringUtils.isBlank(passWord)){
            throw new Exception("该用户密码为空!");
        }

        log.info("开始查询数据源{},信息",dataSourceUrl,userName,passWord);
        List<Map<String,Object>> listInfos = new ArrayList<>();

        Connection conn = getDataSourceConn(dataSourceUrl,userName,passWord);
        log.info("-------数据源初始化结束------");
        //获取链接元数据信息。
        DatabaseMetaData metaData = conn.getMetaData();
        List<Map<String, String>> tableList = this.getTableList(metaData,dataSourceUrl,userName);

        for (Map<String, String> stringMap : tableList) {
            Map<String,Object> tableInfoMap = new HashMap<>();
            for (String ss : stringMap.keySet()) {
                tableInfoMap.put("tableName",ss);
                List<TableInfoQueyVO> tableFields = this.getTableFields(metaData, ss,dataSourceUrl,userName);
                tableInfoMap.put("tableFields",tableFields);
            }
            listInfos.add(tableInfoMap);
        }
        //关闭链接
        closeConnection(conn);
        log.info("查询数据源信息处理结束!");
        return listInfos;
    }

    /**
     * 获取数据库 链接
     * @param dataSourceUrl
     * @param userName
     * @param passWord
     * @return
     * @throws Exception
     */
    public Connection getDataSourceConn(String dataSourceUrl,String userName,String passWord) throws Exception{
        log.info("-------数据源初始化开始------");
        Properties pros = new Properties();
        pros.setProperty("user",userName);
        pros.setProperty("password",passWord);
        pros.setProperty("remarks","true");
        if (dataSourceUrl.contains("mysql")){
          //需要加入个可以获取 REMARKS 的信息,不然获取到的为空
            pros.setProperty("useInformationSchema","true");
            Class.forName("com.mysql.cj.jdbc.Driver").newInstance();
        }else if (dataSourceUrl.contains("oracle")){
            Class.forName("oracle.jdbc.driver.OracleDriver").newInstance();
        }else {
            throw new Exception("不支持的数据类型");
        }

//        DriverManager.getConnection(dataSourceUrl,userName,passWord);
        return DriverManager.getConnection(dataSourceUrl,pros);

    }

    /**
     * 获取该数据源下 所有的列表
     * @param metaData
     * @param dataSourceUrl
     * @return
     * @throws Exception
     */
    public List<Map<String,String>> getTableList(DatabaseMetaData metaData,String dataSourceUrl,String userName) throws Exception{

        log.info("-------获取数据库表 列表开始---------");
        List<Map<String,String>> tableInfoList = new ArrayList<>();

        String dataBaseName = null;
        if (dataSourceUrl.contains("mysql")){
            dataBaseName =dataSourceUrl.substring(dataSourceUrl.lastIndexOf("/")+1,dataSourceUrl.indexOf("?"));
            userName = null;
        }

        ResultSet tables = metaData.getTables(dataBaseName, userName, "%", new String[]{"TABLE"});

        while (tables.next()){
            Map<String,String> tableInfoMap = new HashMap<>();
            tableInfoMap.put(tables.getString("TABLE_NAME"),tables.getString("REMARKS"));
            tableInfoList.add(tableInfoMap);
        }
        //打印测试表
        log.info("-------获取数据库表 列表结束---------");
        return tableInfoList;
    }

    /**
     * 获取表中,所有的表的字段
     * @param metaData
     * @param tableName
     * @param dataSourceUrl
     * @return
     * @throws Exception
     */
    public List<TableInfoQueyVO> getTableFields(DatabaseMetaData metaData,String tableName,String dataSourceUrl,String userName) throws Exception{
        List<TableInfoQueyVO> tableFieldList = new ArrayList<>();
				//兼容oracle和mysql
        String dataBaseName = null;
        if (dataSourceUrl.contains("mysql")){
            dataBaseName =dataSourceUrl.substring(dataSourceUrl.lastIndexOf("/")+1,dataSourceUrl.indexOf("?"));
            userName = null;
        }
        //mysql 使用dataBaseName ,oracle 使用 userName
        ResultSet dataColumns = metaData.getColumns(dataBaseName, userName, tableName, "%");
        ResultSet keys = metaData.getPrimaryKeys(dataBaseName, null, tableName);

        Object entityInstance = this.getEntityInstance(getClassNameList(tableName));

        Map<String,String> breakMap = new HashMap<>();
         while(null!=dataColumns&&dataColumns.next()){
            TableInfoQueyVO tiqv = new TableInfoQueyVO();
            if (!StringUtils.isEmpty(breakMap.get(dataColumns.getString("COLUMN_NAME")))){
                break;
            }

            breakMap.put(dataColumns.getString("COLUMN_NAME"),dataColumns.getString("TYPE_NAME"));
             //比较字段值
            if (this.compareFieldType(dataColumns.getString("COLUMN_NAME"),
                     dataColumns.getString("TYPE_NAME"),entityInstance)){
                 tiqv.setFieldType(dataColumns.getString("TYPE_NAME"));
            }
            tiqv.setFieldCode(dataColumns.getString("COLUMN_NAME"));
            tiqv.setFieldName(dataColumns.getString("REMARKS"));
//            tiqv.setFieldType(dataColumns.getString("TYPE_NAME"));

            String primaryKey = null;
            if (null!=keys&&keys.next()){
                primaryKey = keys.getString("COLUMN_NAME");
                String primaryKeyType = keys.getString("PK_NAME");
                if ("PRIMARY".equals(primaryKeyType)&&primaryKey.equals(tiqv.getFieldCode())){
                    tiqv.setIsKey(primaryKey);
                }

            }
            tableFieldList.add(tiqv);
        }
        breakMap.clear();
        return tableFieldList;
    }

    /**
     * 关闭链接
     * @param conn
     * @throws Exception
     */
    public void closeConnection(Connection conn) throws Exception{
        if (conn.isClosed()){
            log.info("数据源链接已关闭!");
            return;
        }else {
            conn.close();
            log.info("数据源链接关闭结束");
        }
    }

    /**
     * 获取实体对象实例
     * @param className
     * @return
     * @throws Exception
     */
    public Object getEntityInstance(List<String> className) throws Exception{

        Class<?> aClass;

        for (String s : className) {
            try {
                aClass = Class.forName(s);
            } catch (ClassNotFoundException e) { //如果是不存在的地址,继续
                continue;
            }
            if (null != aClass){
                return aClass.newInstance();
            }
        }
        return null;
    }

    /**
     * 获取 实例所在的地址
     * @param tableName
     * @return
     */
    public List<String> getClassNameList(String tableName){

        //新增工程目录需要在这里新增 entity 路径
        List<String> classPathList = new ArrayList<>();
        classPathList.add("cn.com.yusys.yusp.base.data.domain.entity.");
        classPathList.add("cn.com.yusys.yusp.base.engine.domain.entity.");
        classPathList.add("cn.com.yusys.yusp.data.domain.entity.");
        classPathList.add("cn.com.yusys.yusp.message.entity.");
        classPathList.add("cn.com.yusys.yusp.notice.entity.");
        classPathList.add("cn.com.yusys.yusp.oca.domain.entity.");
        classPathList.add("cn.com.yusys.yusp.strategy.data.domain.entity.");
        classPathList.add("cn.com.yusys.yusp.strategy.engine.domain.entity.");
        classPathList.add("cn.com.yusys.yusp.strategy.manager.domain.entity.");
        classPathList.add("cn.com.yusys.yusp.stream.engine.domain.entity.");
        classPathList.add("cn.com.yusys.yusp.stream.manager.domain.entity.");
        classPathList.add("cn.com.yusys.yusp.untiy.domain.entity.");
        classPathList.add("cn.com.yusys.yusp.warning.data.domain.entity.");
        classPathList.add("cn.com.yusys.yusp.warning.engine.domain.entity.");

        List<String> classPathContent = new ArrayList<>();

        String[] split = tableName.split("_");
        String tableNameTmpA = "";
        //实体类类型拼接
        for (String s : split) {
            tableNameTmpA = tableNameTmpA+org.apache.commons.lang.StringUtils.capitalize(s);
        }
        String tableNameTmpB = "";
        for (int i = 1; i < split.length; i++) {
            tableNameTmpB = tableNameTmpB+org.apache.commons.lang.StringUtils.capitalize(split[i]);
        }
        //组装成全路径,并保存,因为不确定 entity 到底是那种,所有两种都组装
        for (String s : classPathList) {
            classPathContent.add(s+tableNameTmpA+"Entity");
            classPathContent.add(s+tableNameTmpA+"Entity");
        }

        return classPathContent;

    }

    /**
     * 比较数据库中字段类型和实体类中的类型是否一致
     * @param fieldName
     * @param fieldType
     * @param entityInstance
     * @return
     */
    public boolean compareFieldType(String fieldName,String fieldType,Object entityInstance){

        if (org.springframework.util.StringUtils.isEmpty(entityInstance)){
            return true;
        }
        Field[] declaredFields = entityInstance.getClass().getDeclaredFields();
        if (org.springframework.util.StringUtils.isEmpty(declaredFields)){
            return false;
        }
        String[] split = fieldName.split("_");
        String fieldNameTmp = split[0].toLowerCase();
        for (int i = 1; i < split.length; i++) {
            fieldNameTmp = fieldNameTmp+org.apache.commons.lang.StringUtils.capitalize(split[i].toLowerCase());
        }

        for (Field declaredField : declaredFields) {
            //字段为空 继续下次循环
            if (org.springframework.util.StringUtils.isEmpty(declaredField)){
                continue;
            }
            //未知数据类型
            if (StringUtils.isBlank(FieldTypeRef.getRefTypeCode(fieldType))){
                return false;
            }
            //如果字段名一致,且字段在映射项中
            if (fieldNameTmp.equals(declaredField.getName())
                    &&declaredField.getType().getName().contains(FieldTypeRef.getRefTypeCode(fieldType))){
                return true;
            }

        }
        return false;
    }
    public List<Map<String,String>> getTableInfoList(DatabaseMetaData metaData,String dataSourceUrl,String userName) throws Exception{

        log.info("-------获取数据库表 列表开始---------");
        List<Map<String,String>> tableInfoList = new ArrayList<>();

        String dataBaseName = null;
        if (dataSourceUrl.contains("mysql")){
            dataBaseName =dataSourceUrl.substring(dataSourceUrl.lastIndexOf("/")+1,dataSourceUrl.indexOf("?"));
            userName = null;
        }

        ResultSet tables = metaData.getTables(dataBaseName, userName, "%", new String[]{"TABLE"});

        while (tables.next()){
            Map<String,String> tableInfoMap = new HashMap<>();
            tableInfoMap.put("tableCode",tables.getString("TABLE_NAME"));
            tableInfoMap.put("tableName",tables.getString("REMARKS"));
            tableInfoList.add(tableInfoMap);

        }
        //打印测试表
        log.info("-------获取数据库表 列表结束---------");
        return tableInfoList;
    }
}

/**
 * 字段类型枚举类
 */
enum FieldTypeRef{

    VAR("VARCHAR","String"),
    TEXT("TEXT","String"),
    INT("INT","Integer"),
    DATETIME("DATETIME","Date"),
    CHAR("CHAR","String"),
    DECIMAL("DECIMAL","BigDecimal"),
    FLOAT("FLOAT","float")
    ;

    private String typeCode;
    private String refTypeCoe;

    public String getTypeCode() {
        return typeCode;
    }

    public void setTypeCode(String typeCode) {
        this.typeCode = typeCode;
    }

    public String getRefTypeCoe() {
        return refTypeCoe;
    }

    public void setRefTypeCoe(String refTypeCoe) {
        this.refTypeCoe = refTypeCoe;
    }

    FieldTypeRef(String typeCode, String refTypeCoe) {
        this.typeCode = typeCode;
        this.refTypeCoe = refTypeCoe;
    }

    public static String getRefTypeCode(String key){

        for (FieldTypeRef value : FieldTypeRef.values()) {
            if (key.equals(value.typeCode)){
                return value.getRefTypeCoe();
            }
        }
        return null;
    }
}

getTables

检索给定目录中可用表的描述。仅返回与目录、模式、表名称和类型条件匹配的表描述。它们按 TABLE_TYPE、TABLE_CAT、TABLE_SCHEM 和 TABLE_NAME 排序。

/**
     * 检索给定目录中可用表的描述。
     * 只有与目录、模式、表匹配的表描述
     * 返回名称和类型标准。他们被订购
     * <code>TABLE_TYPE</code>, <code>TABLE_CAT</code>,
     * <code>TABLE_SCHEM</code> 和 <code>TABLE_NAME</code>。
     * <P>
     * 每个表描述都有以下列:
     * <OL>
     * <LI><B>TABLE_CAT</B> String {@code =>} 表目录(可能是<code>null</code>)
     * <LI><B>TABLE_SCHEM</B> 字符串 {@code =>} 表模式(可能是 <code>null</code>)
     * <LI><B>TABLE_NAME</B> 字符串 {@code =>} 表名
     * <LI><B>TABLE_TYPE</B> 字符串 {@code =>} 表类型。典型的类型是“TABLE”,
     *“视图”、“系统表”、“全局临时”、
     *“本地临时”、“别名”、“同义词”。
     * <LI><B>REMARKS</B> String {@code =>} 对表格的解释性注释
     * <LI><B>TYPE_CAT</B> String {@code =>} 类型目录(可能是<code>null</code>)
     * <LI><B>TYPE_SCHEM</B> String {@code =>} 类型模式(可能是 <code>null</code>)
     * <LI><B>TYPE_NAME</B> String {@code =>} 类型名称(可能是<code>null</code>)
     * <LI><B>SELF_REFERENCING_COL_NAME</B> String {@code =>} 指定名称
     * 类型表的“标识符”列(可能是 <code>null</code>)
     * <LI><B>REF_GENERATION</B> String {@code =>} 指定值如何在
     * 创建 SELF_REFERENCING_COL_NAME。值为
     *“系统”、“用户”、“派生”。 (可能是 <code>null</code>)
     * </OL>
     *
     * <P><B>注意:</B>有些数据库可能不会返回信息
     * 所有表格。
     *
     * @param catalog 一个目录名;必须与目录名称匹配
     * 存储在数据库中; "" 检索那些没有目录的;
     * <code>null</code> 表示不应该使用目录名称来缩小搜索
     * @param schemaPattern 模式名称模式;必须与架构名称匹配
     * 因为它存储在数据库中; "" 检索那些没有模式的;
     * <code>null</code> 表示不应该使用模式名称来缩小范围搜索
     * @param tableNamePattern 一个表名模式;必须匹配存储在数据库中的表名
     * @param types 表类型列表,必须来自表类型列表
     * 从 {@link #getTableTypes} 返回,包括; <code>null</code> 返回所有类型
     * @return <code>ResultSet</code> - 每行是一个表描述
     * @exception SQLException 如果发生数据库访问错误
     * @see #getSearchStringEscape
     */

参数:

​ String catalog: mysql下就是数据库名称,oracle下就是instance名;可以为null,可以为“”。解释参见@param catalog

​ String schemaPattern:mysql下就是数据库名称,oracle中就是用户名.解释参见@param schemaPattern

​ String tableNamePattern: 数据表名称

​ String[] types: 查询的表类型,参考注解中的解释

getColumns

 /**
     * 检索可用的表列的描述
     * 指定目录。
     *
     * <P>只有与目录、模式、表匹配的列描述
     * 和列名条件被返回。他们被订购
     * <code>TABLE_CAT</code>,<code>TABLE_SCHEM</code>,
     * <code>TABLE_NAME</code> 和 <code>ORDINAL_POSITION</code>。
     *
     * <P>每列描述都有以下列:
     * <OL>
     * <LI><B>TABLE_CAT</B> String {@code =>} 表目录(可能是<code>null</code>)
     * <LI><B>TABLE_SCHEM</B> 字符串 {@code =>} 表模式(可能是 <code>null</code>)
     * <LI><B>TABLE_NAME</B> 字符串 {@code =>} 表名
     * <LI><B>COLUMN_NAME</B> 字符串 {@code =>} 列名
     * <LI><B>DATA_TYPE</B> int {@code =>} 来自 java.sql.Types 的 SQL 类型
     * <LI><B>TYPE_NAME</B> String {@code =>} 数据源依赖类型名称,
     * 对于 UDT,类型名称是完全限定的
     * <LI><B>COLUMN_SIZE</B> int {@code =>} 列大小。
     * <LI><B>BUFFER_LENGTH</B> 未使用。
     * <LI><B>DECIMAL_DIGITS</B> int {@code =>} 小数位数。对于其中的数据类型返回 Null
     * DECIMAL_DIGITS 不适用。
     * <LI><B>NUM_PREC_RADIX</B> int {@code =>} 基数(通常为 10 或 2)
     * <LI><B>NULLABLE</B> int {@code =>} 允许为 NULL。
     * <UL>
     * <LI> columnNoNulls - 可能不允许 <code>NULL</code> 值
     * <LI> columnNullable - 绝对允许 <code>NULL</code> 值
     * <LI> columnNullableUnknown - 可空性未知
     * </UL>
     * <LI><B>REMARKS</B> String {@code =>} 注释描述列(可能是<code>null</code>)
     * <LI><B>COLUMN_DEF</B> String {@code =>} 列的默认值,当值用单引号括起来时应解释为字符串(可能为<code>null</code >)
     * <LI><B>SQL_DATA_TYPE</B> int {@code =>} 未使用
     * <LI><B>SQL_DATETIME_SUB</B> int {@code =>} 未使用
     * <LI><B>CHAR_OCTET_LENGTH</B> int {@code =>} 用于 char 类型
     * 列中的最大字节数
     * <LI><B>ORDINAL_POSITION</B> int {@code =>} 表中列的索引
     *(从 1 开始)
     * <LI><B>IS_NULLABLE</B> String {@code =>} ISO 规则用于确定列的可空性。
     * <UL>
     * <LI> YES --- 如果列可以包含 NULL
     * <LI> NO --- 如果列不能包含 NULL
     * <LI> 空字符串 --- 如果
     * 列未知
     * </UL>
     * <LI><B>SCOPE_CATALOG</B> String {@code =>} 范围表的目录
     * 引用属性(如果 DATA_TYPE 不是 REF,则为 <code>null</code>)
     * <LI><B>SCOPE_SCHEMA</B> String {@code =>} 范围表的模式
     * 引用属性(如果 DATA_TYPE 不是 REF,则为 <code>null</code>)
     * <LI><B>SCOPE_TABLE</B> String {@code =>} 这个范围的表名
     * 引用属性(如果 DATA_TYPE 不是 REF,则为 <code>null</code>)
     * <LI><B>SOURCE_DATA_TYPE</B> 短 {@code =>} 不同类型或用户生成的源类型
     * Ref 类型,来自 java.sql.Types 的 SQL 类型(<code>null</code> if DATA_TYPE
     * 不是 DISTINCT 或用户生成的 REF)
     * <LI><B>IS_AUTOINCREMENT</B> String {@code =>} 表示该列是否自动递增
     * <UL>
     * <LI> YES --- 如果列是自动递增的
     * <LI> NO --- 如果列不是自动递增的
     * <LI> 空字符串 --- 如果无法确定列是否自动递增
     * </UL>
     * <LI><B>IS_GENERATEDCOLUMN</B> String {@code =>} 表示这是否是生成列
     * <UL>
     * <LI> YES --- 如果这是一个生成的列
     * <LI> NO --- 如果这不是生成的列
     * <LI> 空字符串 --- 如果无法确定这是否是生成的列
     * </UL>
     * </OL>
     *
     * <p>COLUMN_SIZE 列指定给定列的列大小。
     * 对于数值数据,这是最大精度。对于字符数据,这是字符长度。
     * 对于日期时间数据类型,这是字符串表示的字符长度(假设
     * 小数秒组件的最大允许精度)。对于二进制数据,这是以字节为单位的长度。对于 ROWID 数据类型,
     * 这是以字节为单位的长度。对于其中的数据类型返回 Null
     * 列大小不适用。
     * @param catalog 一个目录名; 必须与目录名称匹配
      * 存储在数据库中; "" 检索那些没有目录的;
      * <code>null</code> 表示不应该使用目录名称来缩小搜索
      * @param schemaPattern 模式名称模式; 
      * 必须与架构名称匹配因为它存储在数据库中; 
      * "" 检索那些没有模式的;
      * <code>null</code> 表示不应该使用模式名称来缩小范围搜索
      * @param tableNamePattern 一个表名模式; 必须匹配
      * 存储在数据库中的表名
      * @param columnNamePattern 列名模式; 必须与列匹配
      * 名称,因为它存储在数据库中
      * @return <code>ResultSet</code> - 每行是一个列描述
      * @exception SQLException 如果发生数据库访问错误
      * @see #getSearchStringEscape
      */

参数

​ String catalog: mysql下就是数据库名称,oracle下就是instance名;可以为null,可以为“”。解释参见@param catalog

​ String schemaPattern:mysql下就是数据库名称,oracle中就是用户名.解释参见@param schemaPattern

​ String tableNamePattern: 数据表名称

​ String columnNamePattern: 列名模式,参考注解中的解释

getPrimaryKeys

getIndexInfo

oracle 和mysql 的 catalog,schema

oracle

Oracle:
server instance == database == catalog: all data managed by same execution engine
schema: namespace within database, identical to user account
user == schema owner == named account: identical to schema, who can connect to database, who owns the schema and use objects possibly in other schemas
to identify any object in running server, you need (schema name + object name)

mysql

MySQL:
server instance == not identified with catalog, just a set of databases
database == schema == catalog: a namespace within the server.
user == named account: who can connect to server and use (but can not own - no concept of ownership) objects in one or more databases
to identify any object in running server, you need (database name)
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值