JDBC实例--JDBC连接池技术解密,连接池对我们不再陌生
一、為什么我們要用連接池技術(shù)?
?
前面的數(shù)據(jù)庫連接的建立及關(guān)閉資源的方法有些缺陷。統(tǒng)艙傳統(tǒng)數(shù)據(jù)庫訪問方式:一次數(shù)據(jù)庫訪問對(duì)應(yīng)一個(gè)物理連接,每次操作數(shù)據(jù)庫都要打開、關(guān)閉該物理連接, 系統(tǒng)性能嚴(yán)重受損。
解決方案:數(shù)據(jù)庫連接池(Connection Pool)。
系統(tǒng)初始運(yùn)行時(shí),主動(dòng)建立足夠的連接,組成一個(gè)池.每次應(yīng)用應(yīng)用程序請求數(shù)據(jù)庫連接時(shí),無需重新打開連接,而是從池中取出已有的連接,使用完后,不再關(guān)閉,而是歸還。
二、連接池主要由三部分組成:連接池的建立、連接池中連接的使用管理、連接池的關(guān)閉。
?
三、連接池技術(shù)的核心思想
?
連接復(fù)用,通過建立一個(gè)數(shù)據(jù)庫連接池以及一套連接使用、分配、管理策略,使得該連接池中的連接可以得到高效、安全的復(fù)用,避免了數(shù)據(jù)庫連接頻繁建立、關(guān)閉的開銷。
1.連接池的建立
在系統(tǒng)初始化時(shí),根據(jù)相應(yīng)的配置創(chuàng)建連接并放置在連接池中,以便需要使用時(shí)能從連接池中獲取,這樣就可以避免連接隨意的建立、關(guān)閉造成的開銷。
?
2.連接池中連接的使用管理
??????連接池管理策略是連接池機(jī)制的核心。當(dāng)連接池建立后,如何對(duì)連接池中的連接進(jìn)行管理,解決好連接池內(nèi)連接的分配和釋放,對(duì)系統(tǒng)的性能有很大的影響。連接的合理分配、釋放可提高連接的復(fù)用,降低了系統(tǒng)建立新連接的開銷,同時(shí)也加速了用戶的訪問速度。
????? 采用的方法是一個(gè)很有名的設(shè)計(jì)模式:Reference Counting(引用記數(shù))。該模式在復(fù)用資源方面應(yīng)用的非常廣泛,把該方法運(yùn)用到對(duì)于連接的分配釋放上,為每一個(gè)數(shù)據(jù)庫連接,保留一個(gè)引用記數(shù),用來記錄該連接的使用者的個(gè)數(shù)。
(1)當(dāng)客戶請求數(shù)據(jù)庫連接時(shí),首先查看連接池中是否有空閑連接(指當(dāng)前沒有分配出去的連接)。如果存在空閑連接,則把連接分配給客戶并作相應(yīng)處理(即標(biāo)記該連接為正在使用,引用計(jì)數(shù)加1)。如果沒有空閑連接,則查看當(dāng)前所開的連接數(shù)是不是已經(jīng)達(dá)到maxConn(最大連接數(shù)),如果沒達(dá)到就重新創(chuàng)建一個(gè)連接給請求的客戶;如果達(dá)到就按設(shè)定的maxWaitTime(最大等待時(shí)間)進(jìn)行等待,如果等待maxWaitTime后仍沒有空閑連接,就拋出無空閑連接的異常給用戶。
(2)當(dāng)客戶釋放數(shù)據(jù)庫連接時(shí),先判斷該連接的引用次數(shù)是否超過了規(guī)定值,如果超過就刪除該連接,并判斷當(dāng)前連接池內(nèi)總的連接數(shù)是否小于minConn(最小連接數(shù)),若小于就將連接池充滿;如果沒超過就將該連接標(biāo)記為開放狀態(tài),可供再次復(fù)用。可以看出正是這套策略保證了數(shù)據(jù)庫連接的有效復(fù)用,避免頻繁地建立、釋放連接所帶來的系統(tǒng)資源開銷。
3.連接池的關(guān)閉
當(dāng)應(yīng)用程序退出時(shí),應(yīng)關(guān)閉連接池,此時(shí)應(yīng)把在連接池建立時(shí)向數(shù)據(jù)庫申請的連接對(duì)象統(tǒng)一歸還給數(shù)據(jù)庫(即關(guān)閉所有數(shù)據(jù)庫連接),這與連接池的建立正好是一個(gè)相反過程。
我們采用DBCP(DataBase connection pool),數(shù)據(jù)庫連接池。DBCP(是 apache 上的一個(gè) java 連接池項(xiàng)目,也是 tomcat 使用的連接池組件。單獨(dú)使用dbcp需要3個(gè)包:commons-dbcp.jar,commons-pool.jar,commons-collections.jar由于建立數(shù)據(jù)庫連接是一個(gè)非常耗時(shí)耗資源的行為,所以通過連接池預(yù)先同數(shù)據(jù)庫建立一些連接,放在內(nèi)存中,應(yīng)用程序需要建立數(shù)據(jù)庫連接時(shí)直接到連接池中申請一個(gè)就行,用完后再放回去。
?
四、連接池的實(shí)現(xiàn)
?
新建一個(gè)java工程并導(dǎo)入相應(yīng)的包。
?
配置文件:
?
1 jdbc.driver=com.mysql.jdbc.Driver 2 jdbc.url=jdbc:mysql://localhost:3306/csdn 3 jdbc.user=root 4 jdbc.password=123456 5 initsize=1 6 maxactive=1 7 maxwait=5000 8 maxidle=1 9 minidle=1?
dbcp的基本配置的介紹
1.initialSize :連接池啟動(dòng)時(shí)創(chuàng)建的初始化連接數(shù)量(默認(rèn)值為0)
2.maxActive :連接池中可同時(shí)連接的最大的連接數(shù)(默認(rèn)值為8,調(diào)整為20,高峰單機(jī)器在20并發(fā)左右,自己根據(jù)應(yīng)用場景定)
3.maxIdle:連接池中最大的空閑的連接數(shù),超過的空閑連接將被釋放,如果設(shè)置為負(fù)數(shù)表示不限制(默認(rèn)為8個(gè),maxIdle不能設(shè)置太小,因?yàn)榧偃缭诟哓?fù)載的情況下,連接的打開時(shí)間比關(guān)閉的時(shí)間快,會(huì)引起連接池中idle的個(gè)數(shù) 上升超過maxIdle,而造成頻繁的連接銷毀和創(chuàng)建,類似于jvm參數(shù)中的Xmx設(shè)置)
4.minIdle:連接池中最小的空閑的連接數(shù),低于這個(gè)數(shù)量會(huì)被創(chuàng)建新的連接(默認(rèn)為0,調(diào)整為5,該參數(shù)越接近maxIdle,性能越好,因?yàn)檫B接的創(chuàng)建和銷毀,都是需要消耗資源的;但是不能太大,因?yàn)樵跈C(jī)器很空閑的時(shí)候,也會(huì)創(chuàng)建低于minidle個(gè)數(shù)的連接,類似于jvm參數(shù)中的Xmn設(shè)置)
5.maxWait? :最大等待時(shí)間,當(dāng)沒有可用連接時(shí),連接池等待連接釋放的最大時(shí)間,超過該時(shí)間限制會(huì)拋出異常,如果設(shè)置-1表示無限等待(默認(rèn)為無限,調(diào)整為60000ms,避免因線程池不夠用,而導(dǎo)致請求被無限制掛起)
DBUtil源碼如下:
1 package com.daliu.jdbc; 2 3 import java.io.InputStream; 4 import java.sql.Connection; 5 import java.sql.SQLException; 6 import java.util.Properties; 7 8 import org.apache.commons.dbcp.BasicDataSource; 9 10 /** 11 * 使用連接池技術(shù)管理數(shù)據(jù)庫連接 12 */ 13 public class DBUtil { 14 15 //數(shù)據(jù)庫連接池 16 private static BasicDataSource dbcp; 17 18 //為不同線程管理連接 19 private static ThreadLocal<Connection> tl; 20 21 //通過配置文件來獲取數(shù)據(jù)庫參數(shù) 22 static{ 23 try{ 24 Properties prop 25 = new Properties(); 26 27 InputStream is 28 = DBUtil.class.getClassLoader() 29 .getResourceAsStream( 30 "com/daliu/jdbc/db.properties"); 31 32 prop.load(is); 33 is.close(); 34 35 //一、初始化連接池 36 dbcp = new BasicDataSource(); 37 38 39 //設(shè)置驅(qū)動(dòng) (Class.forName()) 40 dbcp.setDriverClassName(prop.getProperty("jdbc.driver")); 41 //設(shè)置url 42 dbcp.setUrl(prop.getProperty("jdbc.url")); 43 //設(shè)置數(shù)據(jù)庫用戶名 44 dbcp.setUsername(prop.getProperty("jdbc.user")); 45 //設(shè)置數(shù)據(jù)庫密碼 46 dbcp.setPassword(prop.getProperty("jdbc.password")); 47 //初始連接數(shù)量 48 dbcp.setInitialSize( 49 Integer.parseInt( 50 prop.getProperty("initsize") 51 ) 52 ); 53 //連接池允許的最大連接數(shù) 54 dbcp.setMaxActive( 55 Integer.parseInt( 56 prop.getProperty("maxactive") 57 ) 58 ); 59 //設(shè)置最大等待時(shí)間 60 dbcp.setMaxWait( 61 Integer.parseInt( 62 prop.getProperty("maxwait") 63 ) 64 ); 65 //設(shè)置最小空閑數(shù) 66 dbcp.setMinIdle( 67 Integer.parseInt( 68 prop.getProperty("minidle") 69 ) 70 ); 71 //設(shè)置最大空閑數(shù) 72 dbcp.setMaxIdle( 73 Integer.parseInt( 74 prop.getProperty("maxidle") 75 ) 76 ); 77 //初始化線程本地 78 tl = new ThreadLocal<Connection>(); 79 }catch(Exception e){ 80 e.printStackTrace(); 81 } 82 } 83 84 /** 85 * 獲取數(shù)據(jù)庫連接 86 * @return 87 * @throws SQLException 88 */ 89 public static Connection getConnection() throws SQLException{ 90 /* 91 * 通過連接池獲取一個(gè)空閑連接 92 */ 93 Connection conn 94 = dbcp.getConnection(); 95 tl.set(conn); 96 return conn; 97 } 98 99 100 /** 101 * 關(guān)閉數(shù)據(jù)庫連接 102 */ 103 public static void closeConnection(){ 104 try{ 105 Connection conn = tl.get(); 106 if(conn != null){ 107 /* 108 * 通過連接池獲取的Connection 109 * 的close()方法實(shí)際上并沒有將 110 * 連接關(guān)閉,而是將該鏈接歸還。 111 */ 112 conn.close(); 113 tl.remove(); 114 } 115 }catch(Exception e){ 116 e.printStackTrace(); 117 } 118 } 119 120 /** 121 * 測試是否連接成功 122 * @param args 123 * @throws SQLException 124 */ 125 public static void main(String[] args) throws SQLException { 126 System.out.println(getConnection()); 127 } 128 }
效果如下:
總結(jié)
以上是生活随笔為你收集整理的JDBC实例--JDBC连接池技术解密,连接池对我们不再陌生的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 孕妇梦到板栗是胎梦吗
- 下一篇: 梦到考科二挂了能考过吗