[疯狂Java]JDBC:数据库元数据分析

1. 数据库元数据——有时候并不仅仅需要分析和业务逻辑相关的表,也需要分析当前数据库的有关信息:

    1) 比如分析当前数据库中有多少张表、当前共创建了多少外键、多少索引、某个表的结果如何等等;

    2) 这些都属于描述数据库中数据的数据,称为元数据;

    3) JDBC提供了对数据库元数据分析的API——DatabaseMetaData类对象(通过Connection获得,对象方法,获取本次连接的数据库的元数据对象):

DatabaseMetaData Connection.getMetaData();

!!接着只要调用DatabaseMetaData的各种方法就可以查询数据库的元数据了;


!!接下来要介绍的方法都是DatabaseMetaData的对象方法;

2. 获取数据库的一些厂商信息:

    1) 基本以get作为前缀,最常用的是获取当前数据库的品牌、驱动、版本等信息;

    2) 获取品牌信息:

         i. String getDatabaseProductName();  // 返回品牌名称,MySQL返回的就是"MySQL"

         ii. String getDatabaseProductVersion();  // 返回品牌版本好,MySQL返回的直接就是几点几点几的版本号

    3) 获取驱动信息:驱动信息里肯定包含有connector字符串,因为驱动的本质就是数据库连接器

         i. String getDriverName();  // 返回驱动器名称,MySQL返回的是"MySQL Connector Java"

         ii. String getDriverVersion();  // 返回驱动器版本号,MySQL返回的是"mysql-connector-java-版本号"


3. 了解数据库支持的功能:

    1) 基本以supports作为前缀,返回是否支持某项功能,返回值肯定是boolean;

    2) 常用的两个方法:

         i. boolean supportsCorrelatedSubqueries();  // 是否支持关联子查询

         ii. boolean supportsBatchUpdates();  // 是否支持批处理

!!MySQL这两个功能都支持


4. 查询数据字典中的信息:

    1) 很多方法会基于数据字典(元数据)进行查询,而数据字典也是数据库中的对象(表、索引、视图等等),因此底层也是通过SQL语句实现的,因此这类查询会以ResultSet来返回结果,如果查询信息不可用就返回null;

    2) 这类查询的方法都以get作为前缀;

    3) 首先需要了解的就是数据库支持的表的类型:

         i. 方法是:ResultSet getTableTypes();

         ii. 标准SQL规定了如下几种表的类型:TABLE(用户表)、VIEW(用户视图)、SYSTEM TABLE(系统表,属于数据字典)、SYSTEM VIEW(系统视图,属于数据字典)、LOCAL TEMPORARY(本地临时数据);

    4) 查询数据库中表的信息:

         i. 方法是:ResultSet getTables(String catalog, String schemaPattern, String tableNamePattern, String types[]);

         ii. catalog:表所属的范畴,即查询的表所属的数据库(比如上面例子中的select_test)名称,如果传""表示该表没有所属的数据库,如果传null就表示没有这项筛选条件;

         iii. schemaPattern:表所属的模式,可以使用SQL的通配符%和_,同样""表示没有模式,null表示不使用该项筛选条件

         iv. types:表的类型,即getTableTypes返回的数据库所支持的表的类型,这里是一个String数组的集合

         v. 调用后,会根据参数的筛选信息,把所有符合要求的表都筛选出来然后返回每一张表的相关信息;

    5) 查询数据库中的存储过程:

         i. 方法是: ResultSet getProcedures(String catalog, String schemaPattern, String procedureNamePattern);

         ii. 前两个参数的意义还是老样子,procedureNamePattern就是存储过程的名称,可以使用SQL通配符%和_来过滤;

         iii. 将返回所有符合筛选条件的存储过程的相关信息;

    6) 查询主键:

         i. 方法:ResultSet getPrimaryKeys(String catalog, String schema, String table);

         ii. 主键肯定有所属的表,这里所属的表的表名table必须是精确的,不能有通配符;

         iii. 只要参数名里有pattern就表示这是一个匹配模式,可以使用SQL通配符,如果没有pattern则表示必须完全匹配;

         iv. 会返回所有符合要求的主键的信息

!!这里使用的通配符都是SQL的通配符而不是Java的正则表达式!!

    7) 查询列的信息:

         i. 方法:ResultSet getColumns(String catalog, String schemaPattern, String tableNamePattern, String columnNamePattern);

         ii. tableNamePattern:确定列所属的表的名字,可以用SQL通配符;

         iii. columnNamePattern:列的名字,可以使用通配符

    8) 查询外键:

ResultSet getCrossReference(
    String parentCatalog, String parentSchema, String parentTable,
    String foreignCatalog, String foreignSchema, String foreignTable
);
        i. Catalog、Schema的含义还是老样子;

        ii. table就是表名,这里必须是精确的;

        iii. parent是被参照的表,foreign是主动去参照的表;


5. 示例:

public class Test {
	private String driver;
	private String url;
	private String user;
	private String pass;
	
	public void initParam() throws FileNotFoundException, IOException {
		Properties props = new Properties();
		props.load(new FileInputStream("mysql.ini"));
		driver = props.getProperty("driver");
		url = props.getProperty("url");
		user = props.getProperty("user");
		pass = props.getProperty("pass");
	}
	
	private void showResult(ResultSet rs) throws Exception {
		ResultSetMetaData rsmd = rs.getMetaData();
		
		for (int i = 0; i < rsmd.getColumnCount(); i++) {
			System.out.print('[' + rsmd.getColumnName(i + 1) + ']' + '\t');
		}
		System.out.println();
		
		while (rs.next()) {
			for (int i = 0; i < rsmd.getColumnCount(); i++) {
				System.out.print(rs.getString(i + 1) + '\t');
			}
			System.out.println();
		}
		
		System.out.println();
		rs.close();		
	}
	
	
	public void init() throws Exception {
		initParam();
		Class.forName(driver);
		try (Connection conn = DriverManager.getConnection(url, user, pass)) {
			DatabaseMetaData dbmd = conn.getMetaData();
			
			System.out.println(dbmd.supportsCorrelatedSubqueries());
			System.out.println(dbmd.supportsBatchUpdates());
			
			System.out.println(dbmd.getDatabaseProductName());
			System.out.println(dbmd.getDatabaseProductVersion());
			System.out.println(dbmd.getDriverName());
			System.out.println(dbmd.getDriverVersion());
			
			showResult(dbmd.getTableTypes()); // MySQL支持的表的类型
			showResult(dbmd.getTables(null, null, "%", new String[]{"TABLE"})); // 列出要查找的表
			showResult(dbmd.getPrimaryKeys(null, null, "student_table")); // 列出指定表
			showResult(dbmd.getProcedures(null, null, "%")); // 列出要查找的存储过程
			showResult(dbmd.getCrossReference(null, null, "teacher_table", null, null, "student_table")); // 列出要查找的外键
			showResult(dbmd.getColumns(null, null, "student_table", "%")); // 列出要查找的表的所有列信息(表结构)
		}
	}
	
	public static void main(String[] args) throws Exception {
		new Test().init();
	}

}


6. 直接在MySQL命令行中分析数据字典:这里只讲MySQL的系统表,只在MySQL下存在

    1) MySQL直接提供了一个information_schema数据库,即数据字典,来保存数据库元数据,用户可以直接查询该数据库来获取描述数据库的信息;

    2) information_schema中的数据是不允许用户修改的,这些系统表就相当于视图,只能查看,这是为了避免修改带来的毁灭性灾难;

    3) 常用的系统表:

         i. tables:存放该数据库实例中所有的表的信息;

         ii. views:所有的视图的信息;

         iii. triggers:所有的处触发器的信息;

         iv. rountines:所有的存储过程和函数的信息;

         v. statistics:所有的索引信息;

         vi. table_constraints:所有的表约束信息;

         vii. key_column_usage:列上的键信息;

         viii. columns:所有的列信息;

         ix. schemata:数据库对应的信息(数据库版本等);


7. 选择合适的分析方法:

    1) DatabaseMetaData一般用于应用程序层级,因为其可以轻松实现跨数据库,但是无法更进一步了解数据库更底层的细节;

    2) 直接分析数据库中的数据字典显然会增加和底层的耦合性,一般用于纯数据库层面的静态分析;

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值