JDBC
Java 數(shù)據(jù)庫(kù)連接(Java Database Connectivity,簡(jiǎn)稱JDBC)是 Java 語(yǔ)言中用來(lái)規(guī)范客戶端程序如何來(lái)訪問(wèn)數(shù)據(jù)庫(kù)的應(yīng)用程序接口右冻,提供了諸如查詢和更新數(shù)據(jù)庫(kù)中數(shù)據(jù)的方法冕香。
JDBC 的創(chuàng)建
使用 JDBC 訪問(wèn)數(shù)據(jù)庫(kù)的流程:
- 加載 JDBC 驅(qū)動(dòng)
- 連接數(shù)據(jù)庫(kù)
- 執(zhí)行 SQL 查詢
- 從結(jié)果集中提取數(shù)據(jù)
- 處理結(jié)果集
- 清理環(huán)境改衩,關(guān)閉所有的數(shù)據(jù)庫(kù)資源橙弱,釋放內(nèi)存
關(guān)于 JDBC 更詳細(xì)的介紹與使用:Java-MySQL連接
JDBC 的缺點(diǎn)
熟悉 JDBC 編程的具伍,我們知道它存在很多缺點(diǎn)藕筋,如:
- 數(shù)據(jù)庫(kù)連接纵散,使用時(shí)創(chuàng)建,不使用立即釋放隐圾,對(duì)數(shù)據(jù)庫(kù)進(jìn)行頻繁連接開(kāi)啟和關(guān)閉伍掀,造成數(shù)據(jù)庫(kù)資源浪費(fèi),影響了數(shù)據(jù)庫(kù)的性能暇藏。
- 將 sql 語(yǔ)句硬編碼到j(luò)ava代碼中蜜笤,如果 sql 語(yǔ)句的修改,需要重新編譯java代碼盐碱,不利于系統(tǒng)的維護(hù)
- 向 preparedStatement 中設(shè)置參數(shù)把兔,對(duì)占位符位置和參數(shù)值,硬編碼在代碼中瓮顽,不利于系統(tǒng)的維護(hù)垛贤。
- 從 resultSet 中遍歷結(jié)果集數(shù)據(jù)時(shí),存在硬編碼趣倾,將獲取表的字段進(jìn)行硬編碼聘惦,不利于系統(tǒng)的維護(hù)。
針對(duì)上述缺點(diǎn)儒恋,我們對(duì)應(yīng)的解決方案:
- 問(wèn)題1:使用數(shù)據(jù)庫(kù)的連接池管理數(shù)據(jù)庫(kù)的連接善绎。
- 問(wèn)題2:將 sql 語(yǔ)句配置到 xml 配置文件中,即使 sql 變化诫尽,不需要對(duì) java 進(jìn)行重新編譯
- 問(wèn)題3:將 sql 語(yǔ)句和參數(shù)值配置到 xml 中
- 問(wèn)題4:將查詢的結(jié)果自動(dòng)的映射的 java 的對(duì)象
總的來(lái)說(shuō)禀酱,我們主要會(huì)采用數(shù)據(jù)庫(kù)連接池解決數(shù)據(jù)庫(kù)頻繁鏈接與釋放問(wèn)題,采用配置文件解決 sql 語(yǔ)句硬編碼問(wèn)題牧嫉。
數(shù)據(jù)庫(kù)連接池
連接池技術(shù)的核心思想是:連接復(fù)用剂跟,通過(guò)建立一個(gè)數(shù)據(jù)庫(kù)連接池以及一套連接使用、分配酣藻、管理策略曹洽,使得該連接池中的連接可以得到高效、安全的復(fù)用辽剧,避免了數(shù)據(jù)庫(kù)連接頻繁建立送淆、關(guān)閉的開(kāi)銷。另外怕轿,由于對(duì) JDBC 中的原始連接進(jìn)行了封裝偷崩,從而方便了數(shù)據(jù)庫(kù)應(yīng)用對(duì)于連接的使用(特別是對(duì)于事務(wù)處理)辟拷,提高了開(kāi)發(fā)效率,也正是因?yàn)檫@個(gè)封裝層的存在阐斜,隔離了應(yīng)用的本身的處理邏輯和具體數(shù)據(jù)庫(kù)訪問(wèn)邏輯衫冻,使應(yīng)用本身的復(fù)用成為可能。
連接池的操作:
- 建立數(shù)據(jù)庫(kù)連接池對(duì)象(服務(wù)器啟動(dòng))谒出。
- 按照事先指定的參數(shù)創(chuàng)建初始數(shù)量的數(shù)據(jù)庫(kù)連接(即:空閑連接數(shù))羽杰。
- 對(duì)于一個(gè)數(shù)據(jù)庫(kù)訪問(wèn)請(qǐng)求,直接從連接池中得到一個(gè)連接到推。如果數(shù)據(jù)庫(kù)連接池對(duì)象中沒(méi)有空閑的連接考赛,且連接數(shù)沒(méi)有達(dá)到最大(即:最大活躍連接數(shù)),創(chuàng)建一個(gè)新的數(shù)據(jù)庫(kù)連接莉测。
- 存取數(shù)據(jù)庫(kù)颜骤。
- 關(guān)閉數(shù)據(jù)庫(kù),釋放所有數(shù)據(jù)庫(kù)連接(此時(shí)的關(guān)閉數(shù)據(jù)庫(kù)連接捣卤,并非真正關(guān)閉忍抽,而是將其放入空閑隊(duì)列中。如實(shí)際空閑連接數(shù)大于初始空閑連接數(shù)則釋放連接)董朝。
- 釋放數(shù)據(jù)庫(kù)連接池對(duì)象(服務(wù)器停止鸠项、維護(hù)期間,釋放數(shù)據(jù)庫(kù)連接池對(duì)象子姜,并釋放所有連接)祟绊。
自定義數(shù)據(jù)庫(kù)連接池
大致了解了數(shù)據(jù)庫(kù)連接池的原理與創(chuàng)建方法,我們可以自己編寫一個(gè)數(shù)據(jù)庫(kù)連接池哥捕,而編寫連接池需實(shí)現(xiàn)javax.sql.DataSource
接口牧抽。DataSource
接口中定義了兩個(gè)重載的getConnection
方法:
Connection.getConnection()
Connection.getConnection(String username, String password)
自定義一個(gè)類,實(shí)現(xiàn)DataSource接口遥赚,并實(shí)現(xiàn)連接池功能的步驟:
- 在自定義類的構(gòu)造函數(shù)中批量創(chuàng)建Connection扬舒,并把創(chuàng)建的連接保存到一個(gè)集合對(duì)象中(LinkedList)。
- 在自定義類中實(shí)現(xiàn)Connection.getConnection方法凫佛,讓getConnection方法每次調(diào)用時(shí)讲坎,從集合對(duì)象中取出一個(gè)Connection返回給用戶。
- 當(dāng)用戶使用完Connection愧薛,不能調(diào)用Connection.close()方法晨炕,而要使用連接池提供關(guān)閉方法,即將Connection放回到連接池之中(把Connection存入集合對(duì)象中)厚满。
注:Connection對(duì)象應(yīng)保證將自己返回到連接池的集合對(duì)象中府瞄,而不要把Connection還給數(shù)據(jù)庫(kù)碧磅。
實(shí)際編程時(shí)我們并不需要自己編寫連接數(shù)據(jù)庫(kù)代碼碘箍,有一些開(kāi)源組織提供了數(shù)據(jù)庫(kù)連接池的實(shí)現(xiàn)遵馆,我們只要會(huì)使用即可。在我實(shí)習(xí)的公司丰榴,主要使用以下兩種開(kāi)源數(shù)據(jù)庫(kù)連接池:
- C3P0 數(shù)據(jù)庫(kù)連接池
- DBCP 數(shù)據(jù)庫(kù)連接池
為此货邓,就這兩種數(shù)據(jù)庫(kù)連接池,我做一簡(jiǎn)單的介紹四濒。
C3P0 數(shù)據(jù)庫(kù)連接池
C3P0 是一個(gè)開(kāi)源的 JDBC 連接池换况,它實(shí)現(xiàn)了數(shù)據(jù)源和 JNDI 綁定,支持 JDBC3 規(guī)范和 JDBC2 的標(biāo)準(zhǔn)擴(kuò)展盗蟆。目前使用它的開(kāi)源項(xiàng)目有Hibernate戈二,Spring 等。
C3P0 所需 JAR 包: c3p0-0.9.2.1.jar 和 mchange-commons-java-0.2.3.4.jar
配置文件常用的屬性:
####### c3p0 #######
c3p0.driverClass=com.mysql.jdbc.Driver
c3p0.jdbcUrl=jdbc:mysql://127.0.0.1:3306/test
c3p0.user=xxxx
c3p0.password=xxxxx
c3p0.initialPoolSize=10 //初始化連接數(shù)
c3p0.minPoolSize=10 //最大連接數(shù)
c3p0.maxPoolSize=30 //最小連接數(shù)
c3p0.maxIdleTime=30 //最大空閑時(shí)間 => 這就是為什么C3P0有自動(dòng)回收的原因
c3p0.acquireIncrement=5 //新增連接數(shù)
當(dāng)創(chuàng)建連接池時(shí)喳资,一次性創(chuàng)建initialPoolSize 個(gè)連接觉吭,當(dāng)連接使用完一次性創(chuàng)建 acquireIncrement 個(gè)連接,連接最大數(shù)量 maxPoolSize 仆邓,當(dāng)連接池連接數(shù)量大于 minPoolSize 鲜滩,經(jīng)過(guò) maxIdleTime 連接沒(méi)有使用, 該連接將被釋放节值。
C3P0 連接創(chuàng)建方式主要分為:配置文件形式和硬編碼形式徙硅,這點(diǎn)和 DBCP 數(shù)據(jù)庫(kù)連接池非常相似,唯一不同的就是配置文件命名規(guī)范不同搞疗,C3P0 配置文件必須命名為 c3p0-config.xml 或 c3p0-config.properties ,并且放在 src 目錄下嗓蘑,而 DBCP 沒(méi)有這樣的要求。
DBCP 數(shù)據(jù)庫(kù)連接池
DBCP(DataBase connection pool), 數(shù)據(jù)庫(kù)連接池匿乃。是 apache 上的一個(gè) java 連接池項(xiàng)目脐往,也是 tomcat 默認(rèn)使用的連接池組件。
DBCP 需要3個(gè)包:common-dbcp.jar,common-pool.jar,common-collections.jar
配置文件常用的屬性:
####### dbcp #######
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://127.0.0.1:3306/test
username=xxxx
password=xxxxx
initialSize=10
# maxActive=10 // dbcp2中已將MaxActive設(shè)置為MaxTotal
maxTotal=30 // 可以在這個(gè)池中同時(shí)被分配的有效連接數(shù)的最大值扳埂,如設(shè)置為負(fù)數(shù)业簿,則不限制
maxIdle=10 // 可以在池中保持空閑的最大連接數(shù),超出設(shè)置值之外的空閑連接將被回收阳懂,如設(shè)置為負(fù)數(shù)梅尤,則不限制
minIdle=5 // 可以在池中保持空閑的最小連接數(shù),超出設(shè)置值之外的空閑連接將被創(chuàng)建岩调,如設(shè)置為0巷燥,則不創(chuàng)建
關(guān)于 C3P0 和 DBCP 配置文件更詳細(xì)的說(shuō)明,請(qǐng)自行了解号枕。Demo 可參見(jiàn)我的GitHub倉(cāng)庫(kù)缰揪,后續(xù)會(huì)補(bǔ)充測(cè)試代碼。
C3P0 與 DBCP 區(qū)別
- C3P0 自動(dòng)回收空閑連接
- 主要因?yàn)?
maxIdleTime
屬性葱淳,當(dāng)連接池連接數(shù)量大于minPoolSize
钝腺,經(jīng)過(guò)maxIdleTime
連接沒(méi)有使用抛姑, 該連接將被釋放
- C3P0 擁有 3 種配置方法,DBCP 擁有 2 種配置方法
- 對(duì)數(shù)據(jù)連接的處理方式艳狐,C3P0 提供最大空閑時(shí)間定硝,DBCP 提供最大連接數(shù)
- 前者當(dāng)連接超過(guò)最大空閑連接時(shí)間時(shí),當(dāng)前連接就會(huì)被斷掉毫目。DBCP 當(dāng)連接數(shù)超過(guò)最大連接數(shù)時(shí)蔬啡,所有連接都會(huì)被斷開(kāi)。