数据库连接池技术详解【吐血整理,疯狂推荐】
前言
今天來講一下數(shù)據(jù)庫連接池技術(shù).其實(shí)這個名詞也就是聽起來高大上一點(diǎn),實(shí)際上并不是很復(fù)雜的內(nèi)容,相信在我的講解下,并且自己實(shí)際的將代碼寫一遍之后,能夠?qū)@項技術(shù)有較為深刻的理解.廢話不多說,開始講解.
數(shù)據(jù)庫連接池技術(shù)概述
所謂的數(shù)據(jù)庫連接池技術(shù),就是用來分配,管理,釋放數(shù)據(jù)庫連接的.你也許會問,好像我直接用JDBC也能夠?qū)崿F(xiàn)這些功能吧.
嗯,你說的沒錯,JDBC確實(shí)也可以,但是,你記不記得,我們使用JDBC技術(shù)的時候,每次用完了,是不是都會將連接關(guān)閉;等到下一次再用的時候,是不是都得將數(shù)據(jù)庫連接再打開?
實(shí)際上,數(shù)據(jù)庫鏈接資源是十分寶貴的,我們在小型的項目中還看不出來,在高并發(fā)的項目中,你會發(fā)現(xiàn),這樣頻繁的打開和關(guān)閉數(shù)據(jù)庫鏈接是對服務(wù)器的一種摧殘,十分影響效率.
那么,數(shù)據(jù)庫連接池是如何做的呢?
實(shí)現(xiàn)思路是這樣的:在每次有訪問的時候,數(shù)據(jù)庫連接池會給用戶分配一個數(shù)據(jù)庫連接,當(dāng)用戶用完了連接之后,連接池再將連接回收,放回一個連接集合中.
原理就是這樣的,我們來看一下這張圖加深印象
這樣你可能還是不太清楚,而且,數(shù)據(jù)庫連接池要考慮的東西要比上面說的更復(fù)雜,不過不要害怕,我通過實(shí)際的代碼來幫你理解一下.
備注:下面的代碼是自己實(shí)現(xiàn)一個簡單的數(shù)據(jù)庫連接池,著重了解數(shù)據(jù)庫連接池的原理.
自己實(shí)現(xiàn)一個數(shù)據(jù)庫連接池
注意:下面的代碼我是分塊講解的,你一個個粘貼下來,最后肯定也是能運(yùn)行的,為了方便,我會在講完之后,給出完整的實(shí)現(xiàn)代碼.
- 定義初始化連接數(shù)目,最大連接數(shù)以及當(dāng)前已經(jīng)連接的數(shù)目
一開始,當(dāng)數(shù)據(jù)庫連接池啟動的時候,為了實(shí)現(xiàn)上面的需求,我們肯定是要先給出幾個已經(jīng)完成的連接的,這樣用戶訪問的時候就能直接拿到了;此外,當(dāng)某一段時間的訪問用戶超過我定義的連接池中的連接個數(shù),肯定是要額外新建連接給用戶使用;當(dāng)然,這個新建的連接肯定是不能無限制的,否則還是會很影響效率的,所以,我們還要定義最大的連接數(shù).
- 那么,我們一開始新建的連接池要放在哪里供用戶使用呢?肯定是要創(chuàng)建一個連接集合的,這樣的操作比較方便.至于為什么要使用LinkedList這樣一個集合,一會就會介紹的.
- 剛才說了,一開始我們肯定是要初始化連接給用戶使用的,那么,就需要在連接池啟動的時候就新建一定數(shù)量的鏈接.分析后發(fā)現(xiàn),放在構(gòu)造函數(shù)中初始化鏈接是最好不過的了,最后再將連接放在鏈接集合中.
- 創(chuàng)建一個新的連接,這個就沒啥好說的了,畢竟你要的鏈接都是從這來的.
- 獲取鏈接
當(dāng)用戶來訪問的時候,我們肯定是要給用戶一個連接的,如果池中沒有連接了(所有連接均被占用),那么就要創(chuàng)建新的連接,使用createConnection()函數(shù),當(dāng)然,這個連接的個數(shù)肯定是不能超過最大連接數(shù)的.如果不滿足這兩個條件,那么直接拋出異常.
- 釋放資源
當(dāng)用戶使用完了連接之后,我們要做的并不是關(guān)閉連接,而是將連接重新放入資源池LinkedList之中,這樣就省去了一遍又一遍的連接關(guān)閉.這個就是連接池的核心內(nèi)容.是不是很簡單?
整個的實(shí)現(xiàn)過程就是這樣的,下面我把全部的代碼貼出來,方便大家學(xué)習(xí).
//單元測試 @Test public class MyPool {private final int init_count = 3; //初始化鏈接數(shù)目private final int max_count = 6; //最大private int current_count = 0; //到當(dāng)前連接數(shù)//連接池,用來存放初始化鏈接private LinkedList<Connection> pool = new LinkedList<Connection>();//構(gòu)造函數(shù),初始化鏈接放入連接池public MyPool() {for (int i=0;i<init_count;i++){//記錄當(dāng)前連接數(shù)current_count++;Connection connection = createConnection();pool.addLast(connection);}}//創(chuàng)建新的連接public Connection createConnection() {try {Class.forName("com.mysql.jdbc.Driver");Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/keyan","root","root");return connection;}catch (Exception e){System.out.println("數(shù)據(jù)庫鏈接異常");throw new RuntimeException();}}//獲取鏈接public Connection getConnection() {if (pool.size() > 0){//removeFirst刪除第一個并且返回return pool.removeFirst();}if (current_count < max_count){//記錄當(dāng)前使用的連接數(shù)current_count++;//創(chuàng)建鏈接return createConnection();}throw new RuntimeException("當(dāng)前鏈接已經(jīng)達(dá)到最大連接數(shù)");}//釋放鏈接public void releaseConnection(Connection connection){if (pool.size() < init_count){pool.addLast(connection);current_count--;}else {try {connection.close();} catch (SQLException e) {e.printStackTrace();}}} }自己跑了一遍代碼之后,你是不是發(fā)現(xiàn)原來看起來很復(fù)雜的技術(shù),并不像我們想得那樣?
好了,介紹完了基本的數(shù)據(jù)庫連接池技術(shù)原理之后,我們就要介紹兩個開源的優(yōu)秀的數(shù)據(jù)連接池技術(shù).
其實(shí),真正的數(shù)據(jù)庫連接池要考慮的東西比我們剛才寫的這玩意復(fù)雜,現(xiàn)階段不需要我們寫這樣復(fù)雜的東西,不過如果你感興趣的話,可以看看數(shù)據(jù)庫連接池的源代碼--沒錯,這兩個連接池都是開源的.OK,接下來就開始吧!
優(yōu)秀的數(shù)據(jù)庫連接池
首先,sun公司規(guī)定,連接池技術(shù)需實(shí)現(xiàn)javax.sql.DataSource接口,也就是說,如果你要自己實(shí)現(xiàn)數(shù)據(jù)庫連接池,那么就必須實(shí)現(xiàn)這個接口.是不是很牛比的樣子,實(shí)際上,作為標(biāo)準(zhǔn)制定方,sun公司還是有很多要求的,這是作為標(biāo)準(zhǔn)制定者的權(quán)利,所以,企業(yè)或者國家往往會對一些關(guān)鍵技術(shù)標(biāo)準(zhǔn)的制定打得頭破血流.額,扯遠(yuǎn)了...
DBPC
其實(shí),你可能不知道,如果你的tomcat經(jīng)過特殊的配置,也是可以作為數(shù)據(jù)庫連接池使用的,因?yàn)閠omcat內(nèi)置的就是DBPC…
想要使用DBPC,你必須導(dǎo)入三個jar文件:commons-dbcp2-2.2.0.jar,commons-pool2-2.5.0.jar,commons-logging-1.2.jar.我想,以你的聰明才智,想要獲取這三個jar文件,一定是小菜一疊,這是一個軟件開發(fā)者的必備技能--學(xué)會如何搜索.
使用起來就非常簡單了.使用的方式主要有兩種,一種是硬編碼的方式,就是自己手動設(shè)置各種參數(shù),另外一種就是配置相應(yīng)的配置文件,然后載入就行了.
硬編碼實(shí)現(xiàn)DBPC
BasicDataSource dataSource = new BasicDataSource(); //參數(shù)配置:初始化連接數(shù),最大連接數(shù),連接字符串,驅(qū)動,用戶,密碼 dataSource.setInitialSize(3); //最大初始化鏈接 dataSource.setMaxTotal(6); //最大鏈接 dataSource.setMaxIdle(3000); //最大空閑時間 dataSource.setUrl("jdbc:mysql:///keyan"); //url dataSource.setDriverClassName("com.mysql.jdbc.Driver"); dataSource.setUsername("root"); dataSource.setPassword("root");//獲取鏈接 Connection connection = dataSource.getConnection(); connection.prepareStatement("SELECT * FROM e_person").execute(); connection.close();使用查詢的時候,只需要按照原來JDBC的操作方式就行了,這個沒啥好說的,按照我上面的配置方式實(shí)現(xiàn)就行了,一定不要忘記導(dǎo)入包.
配置文件方式實(shí)現(xiàn)
//創(chuàng)建properties配置文件 Properties properties = new Properties(); //獲取文件流 InputStream in = DBCPTest.class.getResourceAsStream("db.properties"); //加載配置文件 properties.load(in); //創(chuàng)建數(shù)據(jù)源對象 BasicDataSource dataSource = BasicDataSourceFactory.createDataSource(properties);//獲取鏈接 Connection connection = dataSource.getConnection(); ResultSet resultSet = connection.prepareStatement("SELECT * FROM e_person").executeQuery(); while (resultSet.next()){System.out.println(resultSet.getString("work_name")); } connection.close();上面是基本的操作流程,下面我們看一下這個xml文件的配置
文件db.properties
特別要注意的一點(diǎn)是,這個配置文件一定要放在和你的這DBPC類放在同一個包下.
都完成了之后,直接用就可以了.
C3P0
c3p0同樣是非常優(yōu)秀的連接池技術(shù),這個需要導(dǎo)入的文件比較少,只有一個c3p0-0.9.1.2.jar.自己去網(wǎng)站上找一下就好了.
使用c3p0同樣是有兩種方式,分別也是硬編碼方式和配置文件方式.
硬編碼方式
//配置相關(guān)的參數(shù) ComboPooledDataSource dataSource = new ComboPooledDataSource(); dataSource.setJdbcUrl("jdbc:mysql:///keyan"); dataSource.setDriverClass("com.mysql.jdbc.Driver"); dataSource.setUser("root"); dataSource.setPassword("root"); dataSource.setInitialPoolSize(3); dataSource.setMaxPoolSize(6); dataSource.setMaxIdleTime(1000);Connection connection = dataSource.getConnection(); //sql語句 ResultSet resultSet = connection.prepareStatement("SELECT * FROM e_project").executeQuery(); while (resultSet.next()){System.out.println(resultSet.getString("project_name")); } connection.close();和上面一樣,簡單的使用一下就行了,知道如何使用就行.至于更加深層次的東西,有興趣的話慢慢研究吧.
配置文件方式
ComboPooledDataSource dataSource = new ComboPooledDataSource(); Connection connection = dataSource.getConnection(); ResultSet resultSet = connection.prepareStatement("SELECT * FROM e_project").executeQuery(); while (resultSet.next()){System.out.println(resultSet.getString("project_name")); } connection.close();乍一看,你可能會問,不是配置文件方式實(shí)現(xiàn)嗎?沒錯,只是這個是隱式的調(diào)用,不需要你實(shí)現(xiàn),只需要新建一個ComboPooledDataSource對象就行了,默認(rèn)調(diào)用xml文件,文件路徑是src根目錄.也就是說,你只需要將配置文件寫在src目錄下就行了.重點(diǎn)是如何寫這個xml文件.
注意,文件名c3p0-config.xml,這個文件名不能改,必須是這個,文件路徑必須是src根目錄,否則讀取不到.
配置文件的參數(shù)大體上用到的就這么多,當(dāng)然,你也可以去找一下相關(guān)的資料,了解一下更加詳細(xì)的參數(shù)意義,這些參數(shù),我么日常使用足夠了.
補(bǔ)充內(nèi)容:數(shù)據(jù)庫連接池的優(yōu)點(diǎn)
資源重用
由于數(shù)據(jù)庫連接得以重用,避免了頻繁創(chuàng)建,釋放連接引起的大量性能開銷。在減少系統(tǒng)消耗的基礎(chǔ)上,另一方面也增加了系統(tǒng)運(yùn)行環(huán)境的平穩(wěn)性。
更快的系統(tǒng)反應(yīng)速度
數(shù)據(jù)庫連接池在初始化過程中,往往已經(jīng)創(chuàng)建了若干數(shù)據(jù)庫連接置于連接池中備用。此時連接的初始化工作均已完成。對于業(yè)務(wù)請求處理而言,直接利用現(xiàn)有可用連接,避免了數(shù)據(jù)庫連接初始化和釋放過程的時間開銷,從而減少了系統(tǒng)的響應(yīng)時間
新的資源分配手段
對于多應(yīng)用共享同一數(shù)據(jù)庫的系統(tǒng)而言,可在應(yīng)用層通過數(shù)據(jù)庫連接池的配置,實(shí)現(xiàn)某一應(yīng)用最大可用數(shù)據(jù)庫連接數(shù)的限制,避免某一應(yīng)用獨(dú)占所有的數(shù)據(jù)庫資源
統(tǒng)一的連接管理,避免數(shù)據(jù)庫連接泄露:
在較為完善的數(shù)據(jù)庫連接池實(shí)現(xiàn)中,可根據(jù)預(yù)先的占用超時設(shè)定,強(qiáng)制回收被占用連接,從而避免了常規(guī)數(shù)據(jù)庫連接操作中可能出現(xiàn)的資源泄露。
總結(jié)
以上是生活随笔為你收集整理的数据库连接池技术详解【吐血整理,疯狂推荐】的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: DbUtils使用原理详解【不懂的来】
- 下一篇: 【最详细】【传智播客】JavaWeb程序