數(shù)據(jù)庫連接池

# 數(shù)據(jù)庫連接池

### 什么是連接池

數(shù)據(jù)庫連接池負(fù)責(zé)<font color='red'>分配、管理和釋放數(shù)據(jù)庫連接</font>,它允許應(yīng)用程序<font color='red'>重復(fù)使用</font>一個現(xiàn)有的數(shù)據(jù)庫連接,<font color='orange'>而不是再重新建立一個</font>

### 為什么要用連接池

一個數(shù)據(jù)庫連接對象均對應(yīng)一個物理數(shù)據(jù)庫連接,每次操作都打開一個物理連接,使用完都關(guān)閉連接,<font color='cornflowerblue'>這樣造成系統(tǒng)的性能低下</font>。

![img](池.assets/1606768-20190616155729169-544894466.png)

數(shù)據(jù)庫連接池的解決方案是在應(yīng)用程序啟動時建立足夠的數(shù)據(jù)庫連接,并講這些連接組成一個連接池,由應(yīng)用程序動態(tài)地對池中的連接進(jìn)行申請、使用和釋放。

<font color='red'>連接池技術(shù)盡可能多地重用了消耗內(nèi)存地資源,大大節(jié)省了內(nèi)存,提高了服務(wù)器地服務(wù)效率,能夠支持更多的客戶服務(wù)。</font>通過使用連接池,將<font color='orange'>大大提高程序運(yùn)行效率</font>,同時,我們可以通過其自身的管理機(jī)制來監(jiān)視數(shù)據(jù)庫連接的數(shù)量、使用情況等。

### 數(shù)據(jù)庫連接池接口

Java 為數(shù)據(jù)庫連接池提供了公共接口:<font color='red'>javax.sql.DataSource</font>,各大廠商可以讓自己的連接池實(shí)現(xiàn)該接口,而應(yīng)用程序可以方便的切換不同的連接池。

### 數(shù)據(jù)庫連接池的優(yōu)點(diǎn)

- <font color='red'>資源重用</font>

? 由于數(shù)據(jù)庫連接得到重用,避免了頻繁創(chuàng)建、釋放連接引起的大量性能開銷。在減少系統(tǒng)消耗的基礎(chǔ)上,另一方面也增進(jìn)了系統(tǒng)運(yùn)行環(huán)境的平穩(wěn)性(減少內(nèi)存碎片以及數(shù)據(jù)庫臨時進(jìn)程/線程的數(shù)量)。

- <font color='red'>更快的系統(tǒng)響應(yīng)速度</font>

? 數(shù)據(jù)庫連接池在初始化過程中,往往已經(jīng)創(chuàng)建了若干數(shù)據(jù)庫連接置于池中備用。此時連接的初始化工作均已完成。對于業(yè)務(wù)請求處理而言,直接利用現(xiàn)有可用連接,避免了數(shù)據(jù)庫連接初始化和釋放過程的時間開銷,從而縮減了系統(tǒng)整體響應(yīng)時間。

- <font color='red'>新的資源分配手段</font>

? 對于多應(yīng)用共享同一數(shù)據(jù)庫的系統(tǒng)而言,可在應(yīng)用層通過數(shù)據(jù)庫連接的配置,實(shí)現(xiàn)數(shù)據(jù)庫連接池技術(shù),幾年錢也許還是個新鮮話題,對于目前的業(yè)務(wù)系統(tǒng)而言,如果設(shè)計(jì)中還沒有考慮到連接池的應(yīng)用。某一應(yīng)用最大可用數(shù)據(jù)庫連接數(shù)的限制,避免某一應(yīng)用獨(dú)占所有數(shù)據(jù)庫資源。

- <font color='red'>統(tǒng)一的連接管理,避免數(shù)據(jù)庫連接泄漏</font>

? 在較為完備的數(shù)據(jù)庫連接池實(shí)現(xiàn)中,可根據(jù)預(yù)先的連接占用超時設(shè)定,強(qiáng)制收回被占用連接。從而避免了常規(guī)數(shù)據(jù)庫連接操作中可能出現(xiàn)的資源泄漏。

### 數(shù)據(jù)庫連接池的工作原理

分位3步:

- 連接池的建立

- 連接池中連接的使用管理

- 連接池的關(guān)閉

<font color='red'>連接池的建立。</font>一般在系統(tǒng)初始化時,連接池會根據(jù)系統(tǒng)配置建立,并在池中創(chuàng)建了幾個連接對象,以便使用時能從連接池中獲取。<font color='cornflowerblue'>連接池中的連接不能隨意創(chuàng)建和關(guān)閉</font>,這樣避免了連接隨意建立和關(guān)閉造成的系統(tǒng)開銷。

<font color='red'>連接池的管理。</font>連接池管理策略是連接池機(jī)制的核心,連接池內(nèi)連接的分配和釋放對系統(tǒng)的性能有很大的影響。其管理策略是:

```oop

當(dāng)客戶請求數(shù)據(jù)庫連接時,首先查看連接池中是否有空閑連接,如果存在空閑連接,則將連接分配給客戶使用;如果沒有空閑連接,則查看當(dāng)前所開的連接數(shù)是否已經(jīng)達(dá)到最大連接數(shù),如果沒達(dá)到就重新創(chuàng)建一個連接給請求的客戶;如果達(dá)到就按設(shè)定的最大等待時間進(jìn)行等待,如果超出最大等待時間,則拋出異常給客戶。

當(dāng)客戶釋放數(shù)據(jù)庫連接時,先判斷該連接的引用次數(shù)是否超過了規(guī)定值,如果超過就從連接池中刪除該連接,否則保留為其他客戶服務(wù)。

該策略保證了數(shù)據(jù)庫連接的有效復(fù)用,避免頻繁的建立、釋放連接所帶來的系統(tǒng)資源開銷。

```

<font color='red'>連接池的關(guān)閉。</font>當(dāng)應(yīng)用程序退出時,關(guān)閉連接池中所有的連接,釋放連接池相關(guān)的資源,以便連接可以返回池中重復(fù)利用。我們可以通過<font color='orange'>Connection</font>對象的<font color='orange'>Close</font>或<font color='orange'>Dispose</font>方法

## 常用的連接池

| 數(shù)據(jù)庫連接池 | 最新版本? ? | 發(fā)布時間 |

| ------------ | ------------ | -------- |

| c3p0? ? ? ? | c3p0-0.9.5.2 | 2015? ? |

| dbcp? ? ? ? | 2.2.0? ? ? ? | 2017? ? |

| **druid**? ? | 0.11.0? ? ? | 2017? ? |

| **HikariCP** | 2.7.6? ? ? ? | 2018? ? |

#### C3P0

<font color='red'>C3P0</font>在很長一段時間內(nèi),它一直是Java領(lǐng)域內(nèi)數(shù)據(jù)庫連接池的代名詞,當(dāng)年盛極一時的<font color='red'>Hibernate</font>都將其作為內(nèi)置的數(shù)據(jù)庫連接池,可以業(yè)內(nèi)對它的穩(wěn)定性還是認(rèn)可的。<font color='orange'>C3P0功能簡單易用,穩(wěn)定性好這是它的優(yōu)點(diǎn),但是性能上的缺點(diǎn)卻讓它徹底被打入冷宮</font>。<font color='red'>C3P0的性能很差</font>,差到即便是同時代的產(chǎn)品相比它也是墊底的

#### DBCP

屬于Apache頂級項(xiàng)目Commons中的核心子項(xiàng)目(最早在Jakarta Commons里就有),在Apache的生態(tài)圈中的影響里十分廣泛,比如最為大家所熟知的Tomcat就在內(nèi)部集成了DBCP,實(shí)現(xiàn)JPA規(guī)范的<font color='orange'>OpenJPA</font>,也是默認(rèn)集成DBCP的。但DBCP并不是獨(dú)立實(shí)現(xiàn)連接池功能的,它內(nèi)部依賴于Commons中的另一個子項(xiàng)目Pool,連接池最核心的“池”,就是由Pool組件提供的,因?yàn)楹诵墓δ芤蕾囉赑ool,所以DBCP本身只能做小版本的更新,真正大版本的更迭則完全依托于pool。

#### 性能無敵的<font color='red'>HikariCP</font>

- 字節(jié)碼精簡:優(yōu)化代碼,直到編譯后的字節(jié)碼最少,這樣,CPU緩存可以加載更多的程序代碼;

- 優(yōu)化代理和攔截器:減少代碼,例如<font color='orange'>HikariCP</font>的Statement proxy只有100行代碼;

- 自定義數(shù)組類型(<font color='orange'>FastStatementList</font>)代替<font color='orange'>ArrayList</font>:避免每次get()調(diào)用都要進(jìn)行range check,避免調(diào)用remove()時的從頭到尾的掃描;

- 自定義集合類型(<font color='orange'>ConcurrentBag</font>):提高并發(fā)讀寫的效率;

- 其他缺陷的優(yōu)化,比如對于耗時超過一個CPU時間片的方法調(diào)用的研究(但沒說具體怎么優(yōu)化)。

java代碼

```Java

@Test

? ? //Hikari

? ? public void test3() throws Exception{

? ? ? ? Properties properties = new Properties();

? ? ? ? properties.load(PoolTest.class.getClassLoader().getResourceAsStream("hikari.properties"));


? ? ? ? HikariConfig hikariConfig = new HikariConfig(properties);

? ? ? ? DataSource dataSource = new HikariDataSource(hikariConfig);

? ? ? ? System.out.println(dataSource.getConnection());

? ? }

```

properties配置文件

```properties

jdbcUrl=jdbc:mysql://127.0.0.1:3306/job?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai

username=root

password=root

driverClassName=com.mysql.cj.jdbc.Driver

```

#### 功能全面的<font color='red'>Druid</font>(德魯伊)

Druid 相對于其他數(shù)據(jù)庫連接池的優(yōu)點(diǎn)

- 強(qiáng)大的監(jiān)控特性,通過Druid提供的監(jiān)控功能,可以清楚知道連接池和SQL的工作情況。

- 監(jiān)控SQL的執(zhí)行時間、<font color='orange'>ResultSet</font>持有時間、返回行數(shù)、更新行數(shù)、錯誤次數(shù)、錯誤堆棧信息;

-? SQL執(zhí)行的耗時區(qū)間分布。什么是耗時區(qū)間分布呢?比如說,某個SQL執(zhí)行了1000次,其中0\~1毫秒?yún)^(qū)間50次,1\~10毫秒800次,10\~100毫秒100次,100\~1000毫秒30次,1~10秒15次,10秒以上5次。通過耗時區(qū)間分布,能夠非常清楚知道SQL的執(zhí)行耗時情況;

-? 監(jiān)控連接池的物理連接創(chuàng)建和銷毀次數(shù)、邏輯連接的申請和關(guān)閉次數(shù)、非空等待次數(shù)、<font color='orange'>PSCache</font>命中率等。

- 方便擴(kuò)展。Druid提供了Filter-Chain模式的擴(kuò)展API,可以自己編寫Filter攔截JDBC中的任何方法,可以在上面做任何事情,比如說性能監(jiān)控、SQL審計(jì)、用戶名密碼加密、日志等等。

<font color='red'>Druid</font>集合了開源和商業(yè)數(shù)據(jù)庫連接池的優(yōu)秀特性,并結(jié)合<font color='red'>阿里巴巴</font>大規(guī)??量躺a(chǎn)環(huán)境的使用經(jīng)驗(yàn)進(jìn)行優(yōu)化。

| 配置? ? ? ? ? ? ? ? ? ? ? ? ? | 缺省值? ? ? ? ? ? | 說明? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? |

| ----------------------------- | ------------------ | ------------------------------------------------------------ |

| name? ? ? ? ? ? ? ? ? ? ? ? ? |? ? ? ? ? ? ? ? ? ? | 配置這個屬性的意義在于,如果存在多個數(shù)據(jù)源,監(jiān)控的時候? 可以通過名字來區(qū)分開來。如果沒有配置,將會生成一個名字,? 格式是:"DataSource-" + System.identityHashCode(this) |

| jdbcUrl? ? ? ? ? ? ? ? ? ? ? |? ? ? ? ? ? ? ? ? ? | 連接數(shù)據(jù)庫的url,不同數(shù)據(jù)庫不一樣。例如:? mysql : jdbc:mysql://10.20.153.104:3306/druid2? oracle : jdbc:oracle:thin:@10.20.149.85:1521:ocnauto |

| username? ? ? ? ? ? ? ? ? ? ? |? ? ? ? ? ? ? ? ? ? | 連接數(shù)據(jù)庫的用戶名? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? |

| password? ? ? ? ? ? ? ? ? ? ? |? ? ? ? ? ? ? ? ? ? | 連接數(shù)據(jù)庫的密碼。如果你不希望密碼直接寫在配置文件中,? 可以使用ConfigFilter。詳細(xì)看這里:? [https://github.com/alibaba/druid/wiki/%E4%BD%BF%E7%94%A8ConfigFilter](https://github.com/alibaba/druid/wiki/使用ConfigFilter) |

| driverClassName? ? ? ? ? ? ? | 根據(jù)url自動識別? ? | 這一項(xiàng)可配可不配,如果不配置druid會根據(jù)url自動識別dbType,然后選擇相應(yīng)的driverClassName |

| initialSize? ? ? ? ? ? ? ? ? | 0? ? ? ? ? ? ? ? ? | 初始化時建立物理連接的個數(shù)。初始化發(fā)生在顯示調(diào)用init方法,或者第一次getConnection時 |

| maxActive? ? ? ? ? ? ? ? ? ? | 8? ? ? ? ? ? ? ? ? | 最大連接池?cái)?shù)量? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? |

| maxIdle? ? ? ? ? ? ? ? ? ? ? | 8? ? ? ? ? ? ? ? ? | 已經(jīng)不再使用,配置了也沒效果? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? |

| minIdle? ? ? ? ? ? ? ? ? ? ? |? ? ? ? ? ? ? ? ? ? | 最小連接池?cái)?shù)量? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? |

| maxWait? ? ? ? ? ? ? ? ? ? ? |? ? ? ? ? ? ? ? ? ? | 獲取連接時最大等待時間,單位毫秒。配置了maxWait之后,? 缺省啟用公平鎖,并發(fā)效率會有所下降,? 如果需要可以通過配置useUnfairLock屬性為true使用非公平鎖。 |

| poolPreparedStatements? ? ? ? | false? ? ? ? ? ? ? | 是否緩存preparedStatement,也就是PSCache。? PSCache對支持游標(biāo)的數(shù)據(jù)庫性能提升巨大,比如說oracle。? 在mysql5.5以下的版本中沒有PSCache功能,建議關(guān)閉掉。 作者在5.5版本中使用PSCache,通過監(jiān)控界面發(fā)現(xiàn)PSCache有緩存命中率記錄,? 該應(yīng)該是支持PSCache。 |

| maxOpenPreparedStatements? ? | -1? ? ? ? ? ? ? ? | 要啟用PSCache,必須配置大于0,當(dāng)大于0時,? poolPreparedStatements自動觸發(fā)修改為true。? 在Druid中,不會存在Oracle下PSCache占用內(nèi)存過多的問題,? 可以把這個數(shù)值配置大一些,比如說100 |

| validationQuery? ? ? ? ? ? ? |? ? ? ? ? ? ? ? ? ? | 用來檢測連接是否有效的sql,要求是一個查詢語句。? 如果validationQuery為null,testOnBorrow、testOnReturn、? testWhileIdle都不會其作用。 |

| testOnBorrow? ? ? ? ? ? ? ? ? | true? ? ? ? ? ? ? | 申請連接時執(zhí)行validationQuery檢測連接是否有效,做了這個配置會降低性能。 |

| testOnReturn? ? ? ? ? ? ? ? ? | false? ? ? ? ? ? ? | 歸還連接時執(zhí)行validationQuery檢測連接是否有效,做了這個配置會降低性能 |

| testWhileIdle? ? ? ? ? ? ? ? | false? ? ? ? ? ? ? | 建議配置為true,不影響性能,并且保證安全性。? 申請連接的時候檢測,如果空閑時間大于? timeBetweenEvictionRunsMillis,? 執(zhí)行validationQuery檢測連接是否有效。 |

| timeBetweenEvictionRunsMillis |? ? ? ? ? ? ? ? ? ? | 有兩個含義:? 1) Destroy線程會檢測連接的間隔時間? 2) testWhileIdle的判斷依據(jù),詳細(xì)看testWhileIdle屬性的說明 |

| numTestsPerEvictionRun? ? ? ? |? ? ? ? ? ? ? ? ? ? | 不再使用,一個DruidDataSource只支持一個EvictionRun? ? ? ? ? |

| minEvictableIdleTimeMillis? ? |? ? ? ? ? ? ? ? ? ? |? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? |

| connectionInitSqls? ? ? ? ? ? |? ? ? ? ? ? ? ? ? ? | 物理連接初始化的時候執(zhí)行的sql? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? |

| exceptionSorter? ? ? ? ? ? ? | 根據(jù)dbType自動識別 | 當(dāng)數(shù)據(jù)庫拋出一些不可恢復(fù)的異常時,拋棄連接? ? ? ? ? ? ? ? ? |

| filters? ? ? ? ? ? ? ? ? ? ? |? ? ? ? ? ? ? ? ? ? | 屬性類型是字符串,通過別名的方式配置擴(kuò)展插件,? 常用的插件有:? 監(jiān)控統(tǒng)計(jì)用的filter:stat? 日志用的filter:log4j? 防御sql注入的filter:wall |

| proxyFilters? ? ? ? ? ? ? ? ? |? ? ? ? ? ? ? ? ? ? | 類型是List<com.alibaba.druid.filter.Filter>,? 如果同時配置了filters和proxyFilters,? 是組合關(guān)系,并非替換關(guān)系 |

Druid java代碼

```Java

public void test1() throws Exception{

? ? ? ? Properties properties = new Properties();

? ? ? ? properties.load(PoolTest.class.getClassLoader().getResourceAsStream("jdbc.properties"));

? ? ? ? DruidDataSource druidDataSource = new DruidDataSource();

? ? ? ? druidDataSource.configFromPropety(properties);

? ? ? ? Connection connection = druidDataSource.getConnection();

? ? ? ? System.out.println(connection);

? ? }

```

Druid properties配置文件

```properties

druid.url=jdbc:mysql://127.0.0.1:3306/job?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai

druid.username=root

druid.password=root

druid.driverClassName=com.mysql.cj.jdbc.Driver

```

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容