10.9 分析数据库信息
一、使用DatabaseMetaData分析数据库信息
JDBC提供了DatabaseMetaData来封装数据库连接对应数据库的信息,通过Connection提供的getMetaData()方法可以获取数据库对应的DatabaseMetaData对象。
DatabaseMetaData接口通常由驱动程序供应商提供实现,其目的是让用户了解底层数据库的相关信息。使用该接口的目的是发现如何处理底层数据库,所以必须利用该接口来找出底层数据库的功能,例如,调用supportCorrelatedSubqueries()方法查看是否可以使用关联子查询,或者调用supportsBatchUpdates()方法查看是否可以使用批量更新。
许多DatabaseMetaData方法一ResultSet对象的形式返回查询信息,然后使用ResultSet的常规方法(如getString(),getInt())即可从这些ResultSet对象中获取数据。如果查询信息不可用,将返回一个空的ResultSet对象。
DatabaseMetaData的很多方法都需要传入一个xxxPatttern模式字符串,这里的xxxPattern不是正则表达式,而是SQL语句的模式字符串,即用(%)代表任意多个字符,(_)代表一个字符。在通常情况下,如果把该模式字符串的字符串的参数值设置为null,即表示该参数不作为过滤条件。
下面程序通过DatabaseMetaData分析了当前Connection连接对应数据库的一些基本信息,包括当前数据库有多个数据表,存储过程,student_table表的数据列、主键、外键等信息。
package section8;
import java.io.FileInputStream;
import java.sql.*;
import java.util.Properties;
public class DatabaseMetaDataTest
{
private static String driver;
private static String url;
private static String user;
private static String pass;
public void initParam(String fileName)
throws Exception
{
//使用Properties类来加载属性
Properties props=new Properties();
props.load(new FileInputStream(fileName));
driver=props.getProperty("driver");
url=props.getProperty("url");
user=props.getProperty("user");
pass=props.getProperty("pass");
}
public void info()
throws Exception
{
//加载驱动
Class.forName(driver);
try(
//获取数据库连接
Connection conn= DriverManager.getConnection(url,user,pass);
)
{
//获取DatabaseMetaData对象
DatabaseMetaData dbmd=conn.getMetaData();
//获取MySQL支持的所有表类型
ResultSet rs=dbmd.getTableTypes();
System.out.println("--MySQL支持的表类型信息--");
printResultSet(rs);
//获取当前数据库的全部数据表
rs=dbmd.getTables("select_test",null,"%",new String[]{"TABLE"});
System.out.println("--当前数据库的数据表信息--");
printResultSet(rs);
//获取student_table表的主键
rs=dbmd.getPrimaryKeys("select_test",null,"student_table");
System.out.println("--student_table表的主键信息--");
printResultSet(rs);
//获取当前数据库的全部存储过程
rs=dbmd.getProcedures("select_test",null,"%");
System.out.println("--当前数据库的全部存储过程信息--");
printResultSet(rs);
//获取student_table和teacher_table表之间的外键约束
rs=dbmd.getCrossReference("select_test",null,"teacher_table",null,null,"student_table");
System.out.println("--student_table和teacher_table表之间的外键约束--");
printResultSet(rs);
//获取student_table表的全部数据列
rs=dbmd.getColumns("select_test",null,"student_table","%");
System.out.println("--student_table表的全部数据列--");
printResultSet(rs);
}
}
private void printResultSet(ResultSet rs)
throws Exception
{
ResultSetMetaData rsmd=rs.getMetaData();
//打印ResultSet的所有列标题
for(var i=0;i<rsmd.getColumnCount();i++)
{
System.out.print(rsmd.getColumnName(i+1)+"\t");
}
System.out.print("\n");
//打印ResultSet里的全部数据
while(rs.next())
{
for(var i=0;i<rsmd.getColumnCount();i++)
{
System.out.print(rs.getString(i+1)+"\t");
}
System.out.print("\n");
}
}
public static void main(String[] args)
throws Exception
{
var dt=new DatabaseMetaDataTest();
dt.initParam("src\\mysql.ini");
dt.info();;
}
}
二、使用系统表分析数据库信息
除了可以使用DatabaseMetaData来分析底层数据库信息之外,如果已经确定了应用程序所用的数据库系统,则可以通过数据库的系统表来分析数据库信息。系统表又称为数据字典,数据字典的数据通常由数据库系统复杂维护,用户通常只能查询数据字典,而不能修改数据字典的内容。
注意:对于MySQL与SQL Server这样的数据库,它们还提供一个系统数据库来存储这些系统表。系统表相当于视图,用户只能查看系统表的数据,不能直接修改系统表中的数据。
MySQL数据库使用information_schema数据库来保存系统表,在该数据库里包含大量系统表,常用系统表的简单介绍:
(1)tables:存放数据库里所有数据表的信息。
(2)schemata:存放数据库里所有数据库(与MySQL的Schema对应)的信息。
(3)views:存放数据库里所有视图信息。
(4)columns:存放数据库里所有列信息。
(5)routines:存放数据库里所有存储过程和函数信息。
(6)triggers:存放数据库里所有触发器的信息。
(7)key_column_usage:存放数据库里所有具有约束的键信息。
(8)table_constraints:存放数据库里全部约束的表信息。
(9)statistics:存放数据库里全部索引的信息。
三、选择合适的分析方式
通常而言,如果使用DatabaseMetaData来分析数据库信息,则具有很好的跨数据库特性,应用程序可以做到数据库无关;但无法准确获得数据库的更多细节。
使用数据库系统表来分析数据库信息会更加准确,但使用系统表有一个细节——这种方式与底层数据库耦合严重,采用这种方式将会导致程序只能运行于特定的数据库之上。