原理分析之六:元数据(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......