原理分析之六:元数据(metadata)
一、依赖关系
本包对mybatis的其它包没有任何依赖,mybatis的其它包也不依赖于本包,
即本包可以作为单独的组件或者工具类提出来。
二、类功能概述
包含了3个元数据实体类和一个工厂类。
Table是对表的简单封装,包括name,columns,primaryKey,catalog,schema。
Column是对列的简单封装,包括name和type。
Database是对数据库的简单封装,包括catalog,schema,tables。
DatabaseFactory用来创建Database对象。
三、类的方法和属性
//数据库-表格-列
public class Column {
// 列名
private String name;
// 列的类型
private int type;
//构造方法
//getter/setter方法
}
//数据库-表格
public class Table {
//表名
private final String name;
//类别名
private String catalog;
//模式名
private String schema;
//列的集合
private final Map<String, Column> columns = new HashMap<String, Column>();
//主键列
private Column primaryKey;
//构造方法
//getter/setter方法
}
//数据库
public class Database {
// 类别名称;它必须与存储在数据库中的类别名称匹配;该参数为 "" 表示获取没有类别的那些描述;为 null 则表示该类别名称不应该用于缩小搜索范围
private final String catalog;
// schemaPattern - 模式名称的模式;它必须与存储在数据库中的模式名称匹配;该参数为 "" 表示获取没有模式的那些描述;为 null
// 则表示该模式名称不应该用于缩小搜索范围
private final String schema;
// 表格的集合
private final Map<String, Table> tables = new HashMap<String, Table>();
//构造方法
//getter/setter方法
}
本包除了3个实体类封装了 属性和数据结构,只有一个核心方法。
public class DatabaseFactory {
// 根据数据库连接-类别-模式,生成Database对象。
public static Database newDatabase(Connection conn, String catalogFilter,
String schemaFilter) throws SQLException {
Database database = new Database(catalogFilter, schemaFilter);
ResultSet rs = null;
try {
// 数据库元数据
DatabaseMetaData dbmd = conn.getMetaData();
try {
rs = dbmd.getColumns(catalogFilter, schemaFilter, null, null);
// 遍历结果集,取出表的信息,构建Table对象,加入到Databse的Table集合中
while (rs.next()) {
String catalogName = rs.getString("TABLE_CAT");
String schemaName = rs.getString("TABLE_SCHEM");
String tableName = rs.getString("TABLE_NAME");
String columnName = rs.getString("COLUMN_NAME");
int dataType = Integer.parseInt(rs.getString("DATA_TYPE"));
Table table = database.getTable(tableName);
if (table == null) {
table = new Table(tableName);
table.setCatalog(catalogName);
table.setSchema(schemaName);
database.addTable(table);
}
table.addColumn(new Column(columnName, dataType));
}
} finally {
if (rs != null)
rs.close();
}
try {
String[] tableNames = database.getTableNames();
// 遍历所有的Table,取出列名和主键信息
for (int i = 0; i < tableNames.length; i++) {
Table table = database.getTable(tableNames[i]);
rs = dbmd.getPrimaryKeys(catalogFilter, schemaFilter,
table.getName());
if (rs.next()) {
String columnName = rs.getString("COLUMN_NAME");
table.setPrimaryKey(table.getColumn(columnName));
}
}
} finally {
if (rs != null)
rs.close();
}
} finally {
try {
conn.rollback();
} catch (Exception e) {
/* ignore */
}
}
return database;
}
}
四、应用实例
public static void main(String[] args) throws ClassNotFoundException, SQLException {
Connection conn = getConnection();
String catalogFilter = null;
String schemaFilter = null;
Database db = DatabaseFactory.newDatabase(conn, catalogFilter,
schemaFilter);
pn("catalog:" + db.getCatalog());
pn("schema:" + db.getSchema());
String[] tableNames = db.getTableNames();
for (String name : tableNames) {
Table table = db.getTable(name);
p("catalog:"+table.getCatalog()+",");
p("schema:"+table.getSchema()+",");
String[] columnNames = table.getColumnNames();
for (String columnName : columnNames) {
Column column = table.getColumn(columnName);
p(column.getName()+",");
p(column.getType()+",");
}
pn("");
}
if (conn != null) {
conn.close();
}
}
// 简化打印
public static void pn(Object str) {
System.out.println(str);
}
public static void p(Object str) {
System.out.print(str);
}
// 获取数据库连接
public static Connection getConnection() throws ClassNotFoundException,
SQLException {
String driver = "com.mysql.jdbc.Driver";
String url = "jdbc:mysql://localhost:3306/mysql?userUnicode=true&characterEncoding=UTF8";
String user = "root";
String password = "123456";
Class.forName(driver);
return DriverManager.getConnection(url, user, password);
}
打印结果:
catalog:null
schema:null
catalog:mysql,schema:null,Host,1,Table_name,1,Table_priv,1,Column_priv,1,Grantor,1,Db,1,Timestamp,93,User,1,
catalog:mysql,schema:null,Use_leap_seconds,1,Time_zone_id,4
......