生活随笔
收集整理的這篇文章主要介紹了
数据库连接池的设计思路及java实现
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
2019獨角獸企業重金招聘Python工程師標準>>>
connectionPool.DBConnectionManager
[java]?view plain?copy
package?connectionPool;????import?java.sql.Connection;??import?java.sql.Driver;??import?java.sql.DriverManager;??import?java.sql.SQLException;??import?java.util.ArrayList;??import?java.util.Enumeration;??import?java.util.HashSet;??import?java.util.Hashtable;??import?java.util.List;??import?java.util.Map;??import?java.util.Map.Entry;??import?java.util.Set;????import?connectionPool.util.Logger;??import?connectionPool.util.PropertiesMgr;????/**??*?連接池的設計思路??*?1、??*?初始化固定數目的連接(空閑連接與活躍連接在同一池中),建立連接的代理類,添加busy與startTime屬性以便分發與回收連接??*?另建立守護線程回收失效連接??*?2、??*?維護一空閑連接池,初始為空,需要連接時建立,用完的連接回收進入空閑連接池;??*?后續所需連接從空閑連接池獲取;activeNum記錄活躍連接數目;??*?當空閑連接池為空且活躍連接數達到上限時,請求等待,超時即獲取連接失敗,超時前有連接被釋放方可獲得連接??*?第二個設計巧妙優勢明顯,采用第二種方式??*???*?數據庫連接管理類,單例模式??*?可以管理加載多個數據庫驅動,維護多個數據庫連接池??*?@author?shijin??*??*/??public?class?DBConnectionManager?{????????????private?static?DBConnectionManager?dbm?=?null;????????????//單例模式里的成員變量都相當于是static了???????/**??????*?客戶數目??????*/??????private?static?int?clients?=?0;??????/**??????*?加載的驅動器集合??????*/??????private?Set<Driver>?drivers?=?new?HashSet<Driver>();??????/**??????*?數據庫連接池字典??????*/??????private?Hashtable<String,DBConnectionPool>?pools?=?new?Hashtable<String,DBConnectionPool>();????????????private?final?Logger?log?=?Logger.getInstance(DBConnectionPool.class);????????????private?DBConnectionManager()?{??????????loadDrivers();??????????createPools();??????}????????/**??????*?裝載和注冊所有的JDBC驅動程序??????*/??????private?void?loadDrivers()?{??????????String?str_drivers?=?PropertiesMgr.getProperty("driver");??????????for(String?str_driver:str_drivers.split("\\s"))?{??????????????Driver?driver?=?null;??????????????try?{??????????????????driver?=?(Driver)Class.forName(str_driver).newInstance();??????????????????DriverManager.registerDriver(driver);??????????????????log.info("成功加載JDBC驅動:"?+?str_driver);??????????????}?catch?(InstantiationException?e)?{??????????????????log.error("加載JDBC驅動"?+?str_driver?+?"時初始化異常,請檢查配置文件");??????????????}?catch?(IllegalAccessException?e)?{??????????????????log.info("加載JDBC驅動"?+?str_driver?+?"時非法訪問,請檢查配置文件");??????????????}?catch?(ClassNotFoundException?e)?{??????????????????log.info("未找到JDBC驅動"?+?str_driver?+?"請引入相關包");??????????????}?catch?(SQLException?e)?{??????????????????log.info("加載JDBC驅動"?+?str_driver?+?"失敗,請檢查引入包的正確性");??????????????}??????????????drivers.add(driver);??????????}??????}????????/**??????*?根據配置文件創建數據庫連接池??????*/??????private?void?createPools()?{??????????Enumeration<?>?elements?=?PropertiesMgr.propertiesNames();??????????while(elements.hasMoreElements())?{??????????????String?element?=?(String)elements.nextElement();??????????????if(element.endsWith(".url"))?{??????????????????String?poolName?=?element.substring(0,?element.lastIndexOf("."));??????????????????String?url?=?PropertiesMgr.getProperty(poolName?+?".url");??????????????????if(url?==?null)?{??????????????????????log.error("無法連接到數據庫"?+?poolName?+?"請檢查配置文件連接字符串");??????????????????????continue;??????????????????}??????????????????String?user?=?PropertiesMgr.getProperty(poolName?+?".user");??????????????????String?pwd?=?PropertiesMgr.getProperty(poolName?+?".password");??????????????????String?str_max?=?PropertiesMgr.getProperty(poolName?+?".maxconn",?"0");??????????????????int?maxConn?=?0;??????????????????try{??????????????????????maxConn?=?Integer.parseInt(str_max);??????????????????}catch(NumberFormatException?e)?{??????????????????????log.error("數據庫"?+?poolName?+?"最大連接數設置錯誤,默認設為20");??????????????????????maxConn?=?20;??????????????????}?????????????????????????????????DBConnectionPool?pool?=?new?DBConnectionPool(maxConn,url,poolName,user,pwd);??????????????????pools.put(poolName,?pool);??????????????????log.info("成功創建數據庫連接池"?+?poolName);??????????????}??????????}??????}????????/**??????*?獲得單例??????*?@return?DBConnectionManager單例??????*/??????public?synchronized?static?DBConnectionManager?getInstance()?{??????????if(dbm?==?null)?{??????????????dbm?=?new?DBConnectionManager();??????????}??????????clients++;??????????return?dbm;??????}????????/**??????*?從指定連接池中獲取可用連接,無等待??????*?@param?poolName??要獲取連接的連接池名稱??????*?@return??連接池中的一個可用連接或null??????*/??????public?Connection?getConnection(String?poolName)?{??????????DBConnectionPool?pool?=?(DBConnectionPool)pools.get(poolName);??????????return?pool.getConnection();??????}????????????/**??????*?從指定的連接池獲取可用連接,有等待超時??????*?@param?poolName??要獲取連接的連接池名稱??????*?@param?timeout???獲取可用連接的超時時間,單位為秒??????*?@return??????????連接池中的一個可用連接或null??????*/??????public?Connection?getConnection(String?poolName,long?timeout)?{??????????DBConnectionPool??pool?=?(DBConnectionPool)pools.get(poolName);??????????return?pool.getConnection(timeout);??????}????????????/**??????*?回收指定連接池的連接??????*?@param?poolName??連接池名稱??????*?@param?conn??????要回收的連接??????*/??????public?void?freeConnection(String?poolName,Connection?conn)?{??????????DBConnectionPool?pool?=?(DBConnectionPool)pools.get(poolName);??????????if(pool?!=?null)?{??????????????pool.freeConnection(conn);??????????}??????????log.error("找不到連接池,無法回收,請檢查參數");??????}????????????/**??????*?關閉所有連接,撤銷驅動器的注冊??????*/??????public?synchronized?void?release()?{??????????//所有客戶連接都關閉時才真正關閉連接撤銷注冊??????????if(clients--?!=?0)?{??????????????return;??????????}??????????for(Map.Entry<String,DBConnectionPool>?poolEntry:pools.entrySet())?{??????????????DBConnectionPool?pool?=?poolEntry.getValue();??????????????pool.releaseAll();??????????}??????????log.info("已經關閉所有連接");??????????for(Driver?driver:drivers)?{??????????????try?{??????????????????DriverManager.deregisterDriver(driver);??????????????????log.info("撤銷JDBC驅動器"?+?driver.getClass().getName()?+?"的注冊");??????????????}?catch?(SQLException?e)?{??????????????????log.error("撤銷JDBC驅動器"?+?driver.getClass().getName()?+?"的注冊異常");??????????????}??????????}??????????log.info("驅動器撤銷完成");??????}????????????/**??????*?此內部類定義了一個連接池.??????*?它能夠獲取數據庫連接,直到預定的最?大連接數為止??????*?在返回連接給客戶程序之前,它能夠驗證連接的有效性??????*?@author?shijin??????*/??????private?class?DBConnectionPool?{??????????private?int?activeNum?=?0;??????????private?int?maxConn?=?0;??????????private?String?url?=?null;??????????private?String?poolName?=?null;??????????private?String?user?=?null;??????????private?String?pwd?=?null;??????????private?List<Connection>?freeConnections?=?new?ArrayList<Connection>();????????????????????/**??????????*???????????*?@param?maxConn???設定的連接池允許的最大連接數??????????*?@param?url???????數據庫連接url??????????*?@param?poolName??連接池名稱??????????*?@param?user??????數據庫用戶名,或null??????????*?@param?pwd???????數據庫用戶密碼,或null??????????*/??????????public?DBConnectionPool(int?maxConn,?String?url,?String?poolName,??????????????????String?user,?String?pwd)?{??????????????super();??????????????this.maxConn?=?maxConn;??????????????this.url?=?url;??????????????this.poolName?=?poolName;??????????????this.user?=?user;??????????????this.pwd?=?pwd;??????????}????????????????????/**??????????*?獲得一個可用連接,不保證任何情況都能返回一個連接(比如超過最大連接數的時候返回null)??????????*?1、若空閑連接池不為空,從空閑連接池取出一個連接后檢查有效性,正常則返回,失效則重新獲取連接??????????*?2、若空閑連接池為空且未超過最大連接數限制,新建一個連接并返回??????????*?3、空閑連接數為空且超過最大連接數限制,返回null??????????*?@return??獲得的可用連接??????????*/??????????public?synchronized?Connection?getConnection()?{??????????????Connection?conn?=?null;??????????????//空閑連接池中有空閑連接,直接取??????????????if(freeConnections.size()?>?0)?{??????????????????//從空閑連接池中取出一個連接??????????????????conn?=?freeConnections.get(0);??????????????????freeConnections.remove(0);??????????????????//檢測連接有效性??????????????????try{??????????????????????if(conn.isClosed())?{??????????????????????????//由于已經從空閑連接池取出,所以不使用無效連接其就無法重新進入??????????????????????????//空閑連接池,意味著其已經被刪除了,記入日志即可??????????????????????????log.info("從連接池"?+?poolName?+?"中取出的連接已關閉,重新獲取連接");??????????????????????????//繼續從連接池嘗試獲取連接??????????????????????????conn?=?getConnection();??????????????????????}??????????????????}catch(SQLException?e)?{??????????????????????log.info("從連接池"?+?poolName?+?"中取出的發生服務器訪問錯誤,重新獲取連接");??????????????????????conn?=?getConnection();??????????????????}??????????????}?else?if(activeNum?<?maxConn)?{??????????????????conn?=?newConnection();??????????????}?else?{??????????????????//未獲得連接??????????????}??????????????if(conn?!=?null)?{??????????????????activeNum++;??????????????}??????????????return?conn;??????????}????????????????????/**??????????*?當無空閑連接而又未達到最大連接數限制時創建新的連接??????????*?@return??新創建的連接??????????*/??????????private?Connection?newConnection()?{??????????????Connection?conn?=?null;??????????????try{??????????????????if(user?==?null)?{??????????????????????conn?=?DriverManager.getConnection(url);??????????????????}?else?{??????????????????????conn?=?DriverManager.getConnection(url,?user,?pwd);??????????????????}??????????????????log.info("與數據庫"?+?poolName?+?"創建一個新連接");??????????????}catch(SQLException?e)?{??????????????????log.error("無法根據\""?+?url?+?"\"與數據庫"?+?poolName?+?"建立新連接");??????????????}??????????????return?conn;??????????}????????????????????/**??????????*?獲得一個可用連接,超過最大連接數時線程等待,直到有有連接釋放時返回一個可用連接或者超時返回null??????????*?@param?timeout?等待連接的超時時間,單位為秒??????????*?@return??????????*/??????????public?synchronized?Connection?getConnection(long?timeout)?{??????????????Connection?conn?=?null;??????????????long?startTime?=?System.currentTimeMillis();??????????????while((conn?=?getConnection())?==?null)?{??????????????????try{??????????????????????//被notify(),notifyALL()喚醒或者超時自動蘇醒??????????????????????wait(timeout);??????????????????}catch(InterruptedException?e)?{??????????????????????log.error("等待連接的線程被意外打斷");??????????????????}??????????????????//若線程在超時前被喚醒,則不會返回null,繼續循環嘗試獲取連接??????????????????if(System.currentTimeMillis()?-?startTime?>?timeout*1000000)??????????????????????return?null;??????????????}??????????????return?conn;??????????}????????????????????/**??????????*?將釋放的空閑連接加入空閑連接池,活躍連接數減一并激活等待連接的線程??????????*?@param?conn??釋放的連接??????????*/??????????public?synchronized?void?freeConnection(Connection?conn)?{??????????????freeConnections.add(conn);??????????????activeNum--;??????????????notifyAll();//通知正在由于達到最大連接數限制而wait的線程獲取連接??????????}????????????????????/**??????????*?關閉空閑連接池中的所有連接??????????*/??????????public?synchronized?void?releaseAll()?{??????????????for(Connection?conn:freeConnections)?{??????????????????try{??????????????????????conn.close();??????????????????????log.info("關閉空閑連接池"?+?poolName?+?"中的一個連接");??????????????????}catch(SQLException?e)?{??????????????????????log.error("關閉空閑連接池"?+?poolName?+?"中的連接失敗");??????????????????}??????????????}??????????????freeConnections.clear();??????????}??????}??}??connectionpool.util.Logger
[java]?view plain?copy
package?connectionPool.util;????import?java.io.FileWriter;??import?java.io.IOException;??import?java.io.PrintWriter;??import?java.util.Date;????/**??*?日志文件創建維護類,單例模式??*?@author?shijin??*??*/??public?class?Logger?{????????????private?static?Logger?logger=?null;??????private?PrintWriter?log?=?null;??????private?static?int?level?=?0;??????private?Class<?>?c?=?null;??????private?static?final?int?DEBUGLEVEL?=?1;??????private?static?final?int?INFOLEVEL?=?2;??????private?static?final?int?ERRORLEVEL?=?3;????????????private?Logger(Class<?>?c)?{??????????String?logFileName?=?PropertiesMgr.getProperty("logfile","DBlog.txt");??????????String?str_level?=?PropertiesMgr.getProperty("loglevel",?"3");??????????this.c?=?c;??????????level?=?Integer.parseInt(str_level);??????????try?{??????????????log?=?new?PrintWriter(new?FileWriter(logFileName),true);??????????}?catch?(IOException?e)?{??????????????System.err.println("無法打開日志文件"?+?logFileName);??????????????log?=?new?PrintWriter(System.err);??????????}??????}????????????public?synchronized?static?Logger?getInstance(Class<?>?c)?{??????????if(logger?==?null)?{??????????????logger?=?new?Logger(c);??????????}??????????return?logger;??????}??????????????????public?void?debug(String?msg)?{??????????if(level?>?DEBUGLEVEL)?{??????????????msg?=?"DEBUG:"?+?new?Date()?+?"-"?+?msg;??????????????System.out.println(msg);??????????????log.println(msg);??????????}????????????????????}????????????public?void?info(String?msg)?{??????????if(level?>?INFOLEVEL)?{??????????????msg?=?"INFO:"?+?new?Date()?+?"-"?+?msg;??????????????System.out.println(msg);??????????????log.println(msg);??????????}????????????????????}????????????public?void?error(String?msg)?{??????????if(level?>?ERRORLEVEL)?{??????????????msg?=?"ERROR:"?+?new?Date()?+?"-"?+?c?+?"-"?+?msg;??????????????System.out.println(msg);??????????????log.println(msg);??????????}??????}??}??connection.util.PropertiesMgr
[java]?view plain?copy
package?connectionPool.util;????import?java.io.File;??import?java.io.IOException;??import?java.util.Enumeration;??import?java.util.Properties;??/**??*?屬性文件加載管理類,單例模式??*?@author?shijin??*??*/??public?class?PropertiesMgr?{??????private?static?Properties?pro?=?new?Properties();??????private?PropertiesMgr(){}??????static?{??????????try?{??????????????pro.load(PropertiesMgr.class.getClassLoader().getResourceAsStream("config"?+?File.separator?+?"DB.properties"));??????????}?catch?(IOException?e)?{??????????????e.printStackTrace();??????????}??????}????????????public?static?String?getProperty(String?key)?{??????????return?pro.getProperty(key);??????}????????????public?static?String?getProperty(String?key,String?defaultValue)?{??????????//找不到key用defaultValue,而不是說后面為空字符串采用defaultValue??????????return?pro.getProperty(key,?defaultValue);??????}????????????public?static?Enumeration<?>?propertiesNames()?{??????????return?pro.propertyNames();??????}??}??DB.properties
[plain]?view plain?copy
driver=com.mysql.jdbc.Driver????mysql.url=jdbc:mysql://127.0.0.1/caiwu?useUnicode=true&characterEncoding=gb2312????mysql.user=root????mysql.password=123????mysql.maxconn=1000????#\u65E5\u5FD7\u6587\u4EF6\u7684\u540D\u79F0??logfile=??#\u65E5\u5FD7\u7EA7\u522B??loglevel=??
轉載于:https://my.oschina.net/newchaos/blog/1555846
創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎
總結
以上是生活随笔為你收集整理的数据库连接池的设计思路及java实现的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。