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) 直接分析数据库中的数据字典显然会增加和底层的耦合性,一般用于纯数据库层面的静态分析;