Java開發筆記(一百五十一)Druid鏈接池的用法

C3P0鏈接池自誕生以來在Java Web領域反響甚好,業已成爲hibenate框架推薦的鏈接池。誰知人紅是非多,C3P0在大型應用場合中暴露了愈來愈多的侷限性,包括但不限於下列幾點:
一、C3P0管理池內鏈接時沒有采起LRU排隊規則(最久未使用算法),意味着C3P0未能將數據庫性能調到最優。
二、在處理大批量數據的時候,C3P0對耗時操做過於容忍,導致容易出現線程死鎖的情況。
三、C3P0不支持監控功能,外界難以實時跟蹤鏈接池的運行狀況,不利於按需分配和調度系統資源。
就上面幾點問題的見解因人而異,對老外來講,他們國家人口很少,一百年都可貴趕上這種嚴苛的條件,考慮超大規模的數據處理純屬杞人憂天。但對國人來講,數據庫裏的業務記錄動輒以千萬計,億級以上的海量數據也不罕見,此時一點一滴的性能差距彙總起來就可能出大問題。然而C3P0源自國外,人家才懶得搭理這茬事;再說,此等關鍵要害豈能由外人扼住咽喉?固然要本身掌握核心技術才讓人放心,因而阿里巴巴公司推出了國產的開源鏈接池Druid,該鏈接池立足於本國國情,在諸多方面加以調整和優化,比C3P0更適用於國內的業務系統。
Druid的用法近似於C3P0,它擁有本身的鏈接池工具DruidDataSource,該工具的常見方法列舉以下:
setDriverClassName:設置鏈接池的數據庫驅動。
setUrl:設置數據庫的鏈接地址。
setUsername:設置數據庫的用戶名。
setPassword:設置數據庫的密碼。
setInitialSize:設置鏈接池的初始大小。
setMinIdle:設置鏈接池大小的下限。
setMaxActive:設置鏈接池大小的上限。
setRemoveAbandoned:設置是否拋棄已超時的鏈接。
setRemoveAbandonedTimeout:設置超時的時間間隔,單位秒。若是某鏈接超過該時間仍未釋放,則會被自動回收。
setMaxWait:設置獲取鏈接所容許的等待時間,單位毫秒。超過該時間將再也不獲取鏈接。
setTimeBetweenEvictionRunsMillis:設置間隔多久才進行一次檢測,檢測須要關閉的空閒鏈接,單位毫秒。
setValidationQuery:設置檢測鏈接是否有效的SQL語句。
setTestWhileIdle:當空閒時是否須要進行有效性測試。建議設置爲true,保證安全性。
setTestOnBorrow:設置爲true,表示申請鏈接時將調用validationQuery方法來檢測鏈接是否有效。
getDbType:獲取數據庫的名稱。
getActiveCount:獲取活躍鏈接的數量。
getConnectCount:獲取已連上鍊接的數量。
getPoolingCount:獲取空閒鏈接的數量。
getConnection:從鏈接池中獲取一個鏈接,鏈接類型爲DruidPooledConnection。
close:關閉鏈接池。html

至於Druid的編碼過程,則依然分紅兩個步驟:初始化鏈接池、從鏈接池中取出一個鏈接處理,分別說明以下:
一、初始化鏈接池
該步驟首先建立Druid鏈接池的對象,再依次調用相關方法設置詳細的參數信息,包括數據庫驅動、鏈接地址、用戶名、密碼,以及與鏈接池有關的規格參數。下面是初始化Druid鏈接池的代碼例子:算法

	private static DruidDataSource dataSource; // 聲明Druid鏈接池的對象
	// 初始化鏈接池
	private static void initDataSource() {
		dataSource = new DruidDataSource(); // 建立Druid鏈接池
		dataSource.setDriverClassName(driver_class); // 設置鏈接池的數據庫驅動
		dataSource.setUrl(dbUrl); // 設置數據庫的鏈接地址
		dataSource.setUsername(dbUserName); // 設置數據庫的用戶名
		dataSource.setPassword(dbPassword); // 設置數據庫的密碼
		dataSource.setInitialSize(1); // 設置鏈接池的初始大小
		dataSource.setMinIdle(1); // 設置鏈接池大小的下限
		dataSource.setMaxActive(20); // 設置鏈接池大小的上限
	}

  

二、從鏈接池中取出一個鏈接處理
注意該步驟的getConnection方法拿到的是DruidPooledConnection類型的鏈接對象,再根據該鏈接建立對應的報告,並開展後續的數據庫操做。爲方便觀察鏈接池的運行狀況,可在其中添加幾個鏈接池的檢測方法,例如getActiveCount、getConnectCount、getPoolingCount等等。修改後的數據庫操做代碼示例以下:sql

	// 顯示性別分組
	private static void showRecordGroupBySex() {
		String sql = "select sex,count(1) count from teacher group by sex order by sex asc";
		// 從鏈接池中獲取鏈接、建立鏈接的報告、命令報告執行指定的SQL語句
		try (DruidPooledConnection conn = dataSource.getConnection();
				Statement stmt = conn.createStatement();
				ResultSet rs = stmt.executeQuery(sql)) {
			while (rs.next()) { // 循環遍歷結果集裏面的全部記錄
				int sex = rs.getInt("sex"); // 獲取指定字段的整型值
				int count = rs.getInt("count"); // 獲取指定字段的整型值
				String desc = String.format("%s老師有%d位;", sex==0 ? "男" : "女", count);
				System.out.print(desc);
			}
			System.out.println("\ngetActiveCount="+dataSource.getActiveCount()); // 獲取活躍鏈接的數量
			System.out.println("getConnectCount="+dataSource.getConnectCount()); // 獲取已連上鍊接的數量
			System.out.println("getPoolingCount="+dataSource.getPoolingCount()); // 獲取空閒鏈接的數量
		} catch (SQLException e) {
			e.printStackTrace();
		}
	}

 

而後由外部反覆調用以上的showRecordGroupBySex方法,假設準備測試連續的三次數據庫操做,則外部的調用代碼以下所示:數據庫

		for (int i=0; i<3; i++) { // 屢次操做數據庫
			showRecordGroupBySex(); // 顯示性別分組
		}

 

運行包含上面代碼的測試程序,觀察到下面的輸出日誌:安全

男老師有2位;女老師有3位;
getActiveCount=1
getConnectCount=1
getPoolingCount=0
男老師有2位;女老師有3位;
getActiveCount=1
getConnectCount=2
getPoolingCount=0
男老師有2位;女老師有3位;
getActiveCount=1
getConnectCount=3
getPoolingCount=0

 

由日誌可見,getActiveCount方法返回了當前正在使用的鏈接數量,getConnectCount方法返回了曾經連上與已經連上的鏈接總數,getPoolingCount返回了鏈接池中剩餘的鏈接數量。框架



更多Java技術文章參見《Java開發筆記(序)章節目錄工具

相關文章
相關標籤/搜索