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

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)
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/151012.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • rwx

    rwx常用的linux文件权限:444r–r–r–600rw——-644rw-r–r–666rw-rw-rw-700rwx——744rwxr–r–755rwxr-xr-x777rwxrwxrwx从左至右,1-3位数字代表文件所有者的权限,4-6位数字代表同组用户的权限,7-9数字代表其他用户的权限。而具体的权限是由数字来表示的,读取的权限等于4,用r表示;写…

  • 解决导入MySQL数据库提示”Unknown character set: ‘utf8mb4′”错误

    解决导入MySQL数据库提示”Unknown character set: ‘utf8mb4′”错误

  • DNS多点部署IP Anycast+BGP实战分析

    DNS多点部署IP Anycast+BGP实战分析DNS领域的多点部署大多采用IPAnycast+BGP方式,采用这种方式不需要额外采购设备,部署灵活多样。但像其他所有技术一样,IPAnycast+BGP技术只有在适当的领域和范围内才能发挥它的最大优势。Internet不断发展,上网人群数量增加,多数网站或DNS等服务在使用单节点提供服务的情况下,无论服务器性能还是接入带宽都不足以承载大量的用户服务请求;而在国内运营商网络之间访问缓慢的

  • mybatisplus关联表查询_hibernate多表查询

    mybatisplus关联表查询_hibernate多表查询我们在设计表的时候往往一个表的外键作为另一张表的主键,那么我们在查询的时候就要查询两个表的数据。下面来说下实现的方法。数据库表的结构wc_user实体类publicclassWcUserimplementsSerializable{ //用户idprivateStringuserId;//用户密码privateStringus…

  • Matlabinf_matlab怎么定义函数

    Matlabinf_matlab怎么定义函数函数功能在图像处理中,该函数用于获取一张图片的具体信息。这些具体信息包括图片的格式、尺寸、颜色数量、修改时间等等。在matlab的命令窗口中键入docimfinfo或者helpimfinfo都可以得到该函数的帮助信息。调用方式info=imfinfo(filename,fmt)info=imfinfo(filename)程序示例  下面这个程序用于获取位图相关信息。该函数获取位图文件头信…

  • j2EE是什么_J2EE全称

    j2EE是什么_J2EE全称本文简单的介绍了一下J2EE的一些基本知识,下次我们将继续学习J2EE的架构以及API等其他知识。也许我们现在对这些东西都不是很熟悉,但是随着我们的学习深入,这些东西都会理解的。

    2022年10月11日

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号