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

使用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)
  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值