文章來源:https://www.relaxheart.cn/to/master/blog?uuid=76
前言
池(Pool)技術(shù)在一定程度上可以明顯優(yōu)化服務(wù)器應(yīng)用程序的性能,提高程序執(zhí)行效率和降低系統(tǒng)資源開銷。這里所說的池是一種廣義上的池愿卸,比如數(shù)據(jù)庫連接池贺喝、線程池辰如、內(nèi)存池怎栽、對(duì)象池等颊亮。其中剔宪,對(duì)象池可以看成保存對(duì)象的容器拂铡,在進(jìn)程初始化時(shí)創(chuàng)建一定數(shù)量的對(duì)象。需要時(shí)直接從池中取出一個(gè)空閑對(duì)象歼跟,用完后并不直接釋放掉對(duì)象和媳,而是再放到對(duì)象池中以方便下一次對(duì)象請(qǐng)求可以直接復(fù)用。其他幾種池的設(shè)計(jì)思想也是如此哈街,池技術(shù)的優(yōu)勢(shì)是留瞳,可以消除對(duì)象創(chuàng)建所帶來的延遲,從而提高系統(tǒng)的性能骚秦。
要了解Java連接池我們先要了解數(shù)據(jù)庫連接池(connection pool)的原理她倘,Java連接池正是數(shù)據(jù)庫連接池在Java上的應(yīng)用∽鞴浚——我們知道硬梁,對(duì)于共享資源,有一個(gè)很著名的設(shè)計(jì)模式:資源池(Resource Pool)胞得。
該模式正是為了解決資源的頻繁分配﹑釋放所造成的問題荧止。為解決上述問題,可以采用數(shù)據(jù)庫連接池技術(shù)阶剑。數(shù)據(jù)庫連接池的基本思想就是為數(shù)據(jù)庫連接建立一個(gè)“緩沖池”跃巡。預(yù)先在緩沖池中放入一定數(shù)量的連接,當(dāng)需要建立數(shù)據(jù)庫連接時(shí)牧愁,只需從“緩沖池”中取出一個(gè)素邪,使用完畢之后再放回去。我們可以通過設(shè)定連接池最大連接數(shù)來防止系統(tǒng)無盡的與數(shù)據(jù)庫連接猪半。更為重要的是我們可以通過連接池的管理機(jī)制監(jiān)視數(shù)據(jù)庫的連接的數(shù)量﹑使用情況兔朦,為系統(tǒng)開發(fā)﹑測(cè)試及性能調(diào)整提供依據(jù)。
由于自己只是儲(chǔ)備的限制磨确,知道的數(shù)據(jù)庫鏈接池只有JNDI沽甥、C3P0,DBCP,Druid這幾種,今天主要介紹Druid俐填,因?yàn)樵贒ruid的出現(xiàn)是為了替代C3P0安接、DBCP數(shù)據(jù)庫連接池(因?yàn)樗男阅芨?。
Druid介紹
Druid首先是一個(gè)數(shù)據(jù)庫連接池英融。Druid是目前最好的數(shù)據(jù)庫連接池盏檐,在功能、性能驶悟、擴(kuò)展性方面胡野,都超過其他數(shù)據(jù)庫連接池,包括DBCP痕鳍、C3P0硫豆、BoneCP、Proxool笼呆、JBoss DataSource熊响。
Druid已經(jīng)在阿里巴巴部署了超過上千個(gè)應(yīng)用,經(jīng)過一年多生產(chǎn)環(huán)境大規(guī)模部署的嚴(yán)苛考驗(yàn)诗赌。
項(xiàng)目中如果使用Druid
Maven依賴
<druid.version>1.1.6</druid.version>
<mysql-connector-java-version>5.1.44</mysql-connector-java-version>
<!-- https://mvnrepository.com/artifact/com.alibaba/druid -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>${druid.version}</version>
</dependency>
<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysql-connector-java-version}</version>
</dependency>
參數(shù)配置druid.properties
# 數(shù)據(jù)源類型
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
# 數(shù)據(jù)源驅(qū)動(dòng):MySql驅(qū)動(dòng)
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
# 數(shù)據(jù)庫連接URL
spring.datasource.url=jdbc:mysql://localhost:3306/relaxheart?
# 編碼
useUnicode=true&characterEncoding=UTF-8
# 數(shù)據(jù)庫登錄名
datasource.username=root
# 數(shù)據(jù)庫登錄密碼
datasource.password=666666
# 初始化連接數(shù)量
spring.datasource.initialSize=1
# 最小空閑連接數(shù)
spring.datasource.minIdle=1
# 最大并發(fā)連接數(shù)
spring.datasource.maxActive=20
# 配置獲取連接等待超時(shí)的時(shí)間
spring.datasource.maxWait=60000
# 配置間隔多久才進(jìn)行一次檢測(cè)汗茄,檢測(cè)需要關(guān)閉的空閑連接,單位是毫秒
spring.datasource.timeBetweenEvictionRunsMillis=60000
spring.datasource.minEvictableIdleTimeMillis=300000
spring.datasource.validationQuery=SELECT 1 FROM DUAL
spring.datasource.testWhileIdle=true
spring.datasource.testOnBorrow=false
spring.datasource.testOnReturn=false
# 是否開啟PSCache铭若,如果用Oracle洪碳,則把poolPreparedStatements配置為true,mysql可以配置為false
spring.datasource.poolPreparedStatements=false
# 每個(gè)連接上PSCache的大小
spring.datasource.maxPoolPreparedStatementPerConnectionSize=20
# 過濾器
spring.datasource.filters=stat,wall
# 是否打印執(zhí)行SQL
spring.jpa.show-sql=true
數(shù)據(jù)源XML配置
<!-- 數(shù)據(jù)源 -->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"
init-method="init" destroy-method="close">
<!-- 數(shù)據(jù)庫基本信息配置 -->
<property name="url" value="${spring.datasource.url}" />
<property name="username" value="${datasource.username}" />
<property name="password" value="${datasource.password}" />
<property name = "driverClassName" value = "${spring.datasource.driver-class-name}" />
<!-- 初始化連接數(shù)量 -->
<property name="initialSize" value="${spring.datasource.initialSize}" />
<!-- 最小空閑連接數(shù) -->
<property name="minIdle" value="${spring.datasource.minIdle}" />
<!-- 最大并發(fā)連接數(shù) -->
<property name="maxActive" value="${spring.datasource.maxActive}" />
<!-- 配置獲取連接等待超時(shí)的時(shí)間 -->
<property name="maxWait" value="${spring.datasource.maxWait}" />
<!-- 配置間隔多久才進(jìn)行一次檢測(cè)叼屠,檢測(cè)需要關(guān)閉的空閑連接瞳腌,單位是毫秒 -->
<property name="timeBetweenEvictionRunsMillis" value="${spring.datasource.timeBetweenEvictionRunsMillis}" />
<!-- 配置一個(gè)連接在池中最小生存的時(shí)間,單位是毫秒 -->
<property name="minEvictableIdleTimeMillis" value="${spring.datasource.minEvictableIdleTimeMillis}" />
<property name="validationQuery" value="${spring.datasource.validationQuery}" />
<property name="testWhileIdle" value="${spring.datasource.testWhileIdle}" />
<property name="testOnBorrow" value="${spring.datasource.testOnBorrow}" />
<property name="testOnReturn" value="${spring.datasource.testOnReturn}" />
<!-- 打開PSCache镜雨,并且指定每個(gè)連接上PSCache的大小 如果用Oracle嫂侍,則把poolPreparedStatements配置為true,mysql可以配置為false荚坞。 -->
<property name="poolPreparedStatements" value="${spring.datasource.poolPreparedStatements}" />
<property name="maxPoolPreparedStatementPerConnectionSize"
value="${spring.datasource.maxPoolPreparedStatementPerConnectionSize}" />
<!-- 配置監(jiān)控統(tǒng)計(jì)攔截的filters -->
<property name="filters" value="${spring.datasource.filters}" />
</bean>
<!-- 創(chuàng)建SqlSessionFactory,同時(shí)指定數(shù)據(jù)源 -->
<!-- myBatis文件 -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<!-- 配置數(shù)據(jù)庫表對(duì)應(yīng)的java實(shí)體類 -->
<property name="typeAliasesPackage" value="cn.project.dal.object"></property>
<!-- 自動(dòng)掃描entity目錄, 省掉Configuration.xml里的手工配置-->
<property name="mapperLocations" value="classpath:config/mapping/*.xml" />
</bean>
<bean name="projectMapperScannerConfigurer" class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="cn.project.dal.inter"/>
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
</bean>
<!-- ===================事務(wù)定義開始================= -->
<!-- Ibatis事務(wù)管理器 -->
到這Druid數(shù)據(jù)源配置就完成了挑宠。接下來想要擴(kuò)展一點(diǎn)內(nèi)容,
擴(kuò)展點(diǎn)
怎么打開Druid的監(jiān)控統(tǒng)計(jì)功能
Druid的監(jiān)控統(tǒng)計(jì)功能是通過filter-chain擴(kuò)展實(shí)現(xiàn)西剥,如果你要打開監(jiān)控統(tǒng)計(jì)功能痹栖,配置StatFilter,具體看這里:https://github.com/alibaba/druid/wiki/%E9%85%8D%E7%BD%AE_StatFilter
內(nèi)置監(jiān)控中的Web和Spring關(guān)聯(lián)監(jiān)控怎么配置瞭空?
- Web關(guān)聯(lián)監(jiān)控配置
https://github.com/alibaba/druid/wiki/%E9%85%8D%E7%BD%AE_%E9%85%8D%E7%BD%AEWebStatFilter - Spring關(guān)聯(lián)監(jiān)控配置
https://github.com/alibaba/druid/wiki/%E9%85%8D%E7%BD%AE_Druid%E5%92%8CSpring%E5%85%B3%E8%81%94%E7%9B%91%E6%8E%A7%E9%85%8D%E7%BD%AE
怎么配置防御SQL注入攻擊
Druid提供了WallFilter揪阿,它是基于SQL語義分析來實(shí)現(xiàn)防御SQL注入攻擊的。具體配置看這里:https://github.com/alibaba/druid/wiki/%E9%85%8D%E7%BD%AE-wallfilter
Druid有沒有參考配置
不同的業(yè)務(wù)場(chǎng)景需求不同咆畏,你可以使用我們的參考配置南捂,但建議你仔細(xì)閱讀相關(guān)文檔,了解清楚之后做定制配置旧找。https://github.com/alibaba/druid/wiki/%E9%85%8D%E7%BD%AE_DruidDataSource%E5%8F%82%E8%80%83%E9%85%8D%E7%BD%AE
我想日志記錄JDBC執(zhí)行的SQL溺健,如何配置
Druid提供了Log4jFilter、CommonsLogFilter和Slf4jFilter钮蛛,具體配置看這里https://github.com/alibaba/druid/wiki/%E9%85%8D%E7%BD%AE_LogFilter
我的程序可能產(chǎn)生連接泄漏了鞭缭,有什么辦法剖膳?
Druid提供了多種監(jiān)測(cè)連接泄漏的手段,具體看這里:https://github.com/alibaba/druid/wiki/%E8%BF%9E%E6%8E%A5%E6%B3%84%E6%BC%8F%E7%9B%91%E6%B5%8B
在Druid中使用PSCache會(huì)有內(nèi)存占用過大問題么岭辣?
連接Oracle數(shù)據(jù)庫吱晒,打開PSCache,在其他的數(shù)據(jù)庫連接池都會(huì)存在內(nèi)存占用過多的問題沦童,Druid是唯一解決這個(gè)問題的連接池仑濒。具體看這里:https://github.com/alibaba/druid/wiki/Oracle%E6%95%B0%E6%8D%AE%E5%BA%93%E4%B8%8BPreparedStatementCache%E5%86%85%E5%AD%98%E9%97%AE%E9%A2%98%E8%A7%A3%E5%86%B3%E6%96%B9%E6%A1%88
有沒有和其他數(shù)據(jù)庫連接池的對(duì)比?
- 各種數(shù)據(jù)庫連接池對(duì)比https://github.com/alibaba/druid/wiki/%E5%90%84%E7%A7%8D%E6%95%B0%E6%8D%AE%E5%BA%93%E8%BF%9E%E6%8E%A5%E6%B1%A0%E5%AF%B9%E6%AF%94
從其他連接池遷移要注意什么偷遗?
- 不同連接池的參數(shù)參照對(duì)比: http://code.alibabatech.com/wiki/pages/viewpage.action?pageId=6947005
- DBCP遷移 https://github.com/alibaba/druid/wiki/DBCP%E8%BF%81%E7%A7%BB
Druid中有沒有類似Jboss DataSource中的ExceptionSorter
ExceptionSorter是JBoss DataSource中的優(yōu)秀特性墩瞳,Druid也有一樣功能的ExceptionSorter,但不用手動(dòng)配置氏豌,自動(dòng)識(shí)別生效的喉酌。具體看這里:https://github.com/alibaba/druid/wiki/ExceptionSorter_cn
Druid中的maxIdle為什么是沒用的?
maxIdle是Druid為了方便DBCP用戶遷移而增加的箩溃,maxIdle是一個(gè)混亂的概念瞭吃。連接池只應(yīng)該有maxPoolSize和minPoolSize,druid只保留了maxActive和minIdle涣旨,分別相當(dāng)于maxPoolSize和minPoolSize歪架。
我的應(yīng)用配置的是JNDI數(shù)據(jù)源,可以用DruidDataSource么霹陡?
DruidDataSource支持JNDI配置和蚪,具體看這里:https://github.com/alibaba/druid/wiki/%E9%85%8D%E7%BD%AE_JNDI_Tomcat
具體實(shí)現(xiàn)的類是這個(gè):com.alibaba.druid.pool.DruidDataSourceFactory,你可以閱讀代碼加深理解烹棉。
我的應(yīng)用已使用DBCP攒霹,是代碼中寫死的,怎樣更換為Druid浆洗?
可以的催束,Druid提供了一個(gè)中完全平滑遷移DBCP的辦法。
- 從http://repo1.maven.org/maven2/com/alibaba/druid/druid-wrapper/ 下載druid-wrapper-xxx.jar
- 加入druid-xxx.jar
- 從你的WEB-INF/lib/中刪除dbcp-xxx.jar
- 按需要加上配置伏社,比如JVM啟動(dòng)參數(shù)加上-Ddruid.filters=stat抠刺,動(dòng)態(tài)配置druid的filters
這種用法,使得可以在一些非自己開發(fā)的應(yīng)用中使用Druid摘昌,例如在sonar中部署druid速妖,sonar是一個(gè)使用jruby開發(fā)的web應(yīng)用,寫死了DBCP聪黎,只能夠通過這種方法來更換罕容。
我想試用快照版本,怎么獲取锦秒?
直接獲取快照版本的地址是:http://code.alibabatech.com/mvn/snapshots/com/alibaba/druid/
注意:快照版本慎用露泊,可能會(huì)有不可預(yù)知的問題
有一些SQL執(zhí)行很慢,我希望日志記錄下來脂崔,怎么設(shè)置滤淳?
運(yùn)維和DBA都不希望把密碼明文直接寫在配置文件中梧喷,Druid提供了數(shù)據(jù)庫秘密加密的功能砌左。具體看這里:https://github.com/alibaba/druid/wiki/%E4%BD%BF%E7%94%A8ConfigFilter
如何參與Druid的開發(fā)
Druid是一個(gè)通過github開源的項(xiàng)目,github的特性铺敌,使得你很容易參與其中汇歹。這里有詳細(xì)說明https://github.com/alibaba/druid/wiki/%E5%A6%82%E4%BD%95%E5%8F%82%E4%B8%8E
Druid的發(fā)布周期是怎樣?
Druid是一個(gè)活躍的項(xiàng)目偿凭,長(zhǎng)期維護(hù)产弹。每個(gè)月有一個(gè)發(fā)布窗口,除非遇到重大bug和非常緊急的需求弯囊,否則都是每個(gè)月最多發(fā)布一次痰哨。如果沒有足夠多的需求,發(fā)布窗口就不會(huì)被使用匾嘱。
如果DruidDataSource在init的時(shí)候失敗了斤斧,不再使用,是否需要close
是的霎烙,如果DruidDataSource不再使用撬讽,必須調(diào)用close來釋放資源,釋放的資源包括關(guān)閉Create和Destory線程悬垃。
DruidDataSource支持哪些數(shù)據(jù)庫游昼?
mysql 支持,大規(guī)模使用
oracle 支持尝蠕,大規(guī)模使用
sqlserver 支持
postgres 支持
db2 支持
h2 支持
derby 支持
sqlite 支持
sybase 支持
Oracle下jdbc executeBatch時(shí)烘豌,更新行數(shù)計(jì)算不正確
使用jdbc的executeBatch 方法,如果數(shù)據(jù)庫為oracle看彼,則無論是否成功更新到數(shù)據(jù)廊佩,返回值都是-2,而不是真正被sql更新到的記錄數(shù)闲昭,這是Oracle JDBC Driver的問題罐寨,Druid不作特殊處理。
如何保存監(jiān)控記錄
我想Log輸出SQL執(zhí)行的信息怎么辦序矩?
https://github.com/alibaba/druid/wiki/%E9%85%8D%E7%BD%AE_LogFilter