1. 程式人生 > >[瘋狂Java]JDBC:資料庫元資料分析

[瘋狂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) 直接分析資料庫中的資料字典顯然會增加和底層的耦合性,一般用於純資料庫層面的靜態分析;