Java Web開發(fā)實(shí)戰(zhàn)—JDBC進(jìn)階
時(shí)間:2023-05-24 19:00:02 | 來(lái)源:網(wǎng)站運(yùn)營(yíng)
時(shí)間:2023-05-24 19:00:02 來(lái)源:網(wǎng)站運(yùn)營(yíng)
Java Web開發(fā)實(shí)戰(zhàn)—JDBC進(jìn)階:
數(shù)據(jù)庫(kù)事務(wù)事務(wù)的概念事務(wù),是指數(shù)據(jù)庫(kù)中的一個(gè)操作序列,它由一條或多條SQL命令所組成,這些SQL命令不可分割,只有當(dāng)事務(wù)中的所有SQL命令被成功執(zhí)行后,整個(gè)事務(wù)引發(fā)的操作才會(huì)被更新到數(shù)據(jù)庫(kù),如果有一條執(zhí)行失敗,所有操作都將會(huì)被取消。
下面通過(guò)一個(gè)生活實(shí)例來(lái)講解數(shù)據(jù)庫(kù)的事務(wù)?,F(xiàn)在很多商店提供掃碼支付功能,假如李磊購(gòu)物之后需向商家支付500元,其購(gòu)物行為觸發(fā)的SQL語(yǔ)句如下。
這兩條SQL命令屬于同一個(gè)操作序列,只有全部被成功執(zhí)行時(shí),整個(gè)事務(wù)才會(huì)被更新到數(shù)據(jù)庫(kù),否則,全部SQL命令都要被取消。這就避免了李磊賬戶少500元而商家賬戶金額不變的情況。
各大數(shù)據(jù)庫(kù)廠商均提供了對(duì)事務(wù)的支持,接下來(lái)以MySQL為例講解數(shù)據(jù)庫(kù)中事務(wù)的管理。
MySQL數(shù)據(jù)庫(kù)共有兩種方式來(lái)管理事務(wù)。
1. 自動(dòng)提交事務(wù)在默認(rèn)狀態(tài)下,MySQL自動(dòng)提交事務(wù),即每執(zhí)行一條SQL語(yǔ)句就提交一次事務(wù)。這可以通過(guò)MySQL的全局變量autocommit進(jìn)行查看,SQL語(yǔ)句如下。
通過(guò)SQL語(yǔ)句查看當(dāng)前數(shù)據(jù)庫(kù)的事務(wù)狀態(tài),執(zhí)行結(jié)果如下。
從以上執(zhí)行結(jié)果可以看出,全局變量autocommit的值為ON,這時(shí),數(shù)據(jù)庫(kù)事務(wù)是默認(rèn)提交的。
關(guān)閉數(shù)據(jù)庫(kù)自動(dòng)提交事務(wù)的功能,SQL語(yǔ)句如下。
SET AUTOCOMMIT = 0;#0是OFF,1是ON
以上SQL語(yǔ)句的執(zhí)行結(jié)果如下。
mysql> SET AUTOCOMMIT = 0;
Query OK, 0 rows affected (0.00 sec)
再次通過(guò)SQL語(yǔ)句查看當(dāng)前數(shù)據(jù)庫(kù)的事務(wù)狀態(tài),執(zhí)行結(jié)果如下。
從以上執(zhí)行結(jié)果可以看出,全局變量autocommit的值為OFF,這時(shí),數(shù)據(jù)庫(kù)事務(wù)是需要手動(dòng)提交的。
2. 手動(dòng)提交事務(wù)手動(dòng)進(jìn)行事務(wù)管理時(shí),首先要開啟事務(wù)(Start Transaction),再提交(Commit)或回滾(Rollback)事務(wù)。提交事務(wù)會(huì)將整個(gè)事務(wù)中的操作更新到數(shù)據(jù)庫(kù),回滾事務(wù)則會(huì)取消整個(gè)事務(wù)中已執(zhí)行的所有操作。當(dāng)手動(dòng)提交事務(wù)時(shí),上文實(shí)例中購(gòu)物支付觸發(fā)的SQL語(yǔ)句如下。
在實(shí)際的開發(fā)過(guò)程中,事務(wù)是并發(fā)控制的基本單位,將一組操作序列組合為一個(gè)要么全部成功要么全部失敗的單元,可以簡(jiǎn)化錯(cuò)誤,恢復(fù)并使應(yīng)用程序更加可靠。
事務(wù)的ACID屬性ACID,是數(shù)據(jù)庫(kù)事務(wù)正確執(zhí)行的四個(gè)基本要素的縮寫,它包含原子性(Atomicity)、一致性(Consistency)、隔離性(Isolation)、持久性(Durability)。一個(gè)支持事務(wù)的數(shù)據(jù)庫(kù),必需要具有這四種特性,否則在事務(wù)管理中無(wú)法保證數(shù)據(jù)的正確性。
1.原子性(Atomicity)整個(gè)事務(wù)中的所有操作是不可分割的,要么完全執(zhí)行,要么完全不執(zhí)行,不能停滯在中間某個(gè)環(huán)節(jié)。事務(wù)的操作序列如果全部成功,就必須完全應(yīng)用到數(shù)據(jù)庫(kù);如果有一項(xiàng)操作失敗,就不能對(duì)數(shù)據(jù)庫(kù)有任何影響。
2.一致性(Consistent)事務(wù)完成時(shí),數(shù)據(jù)必須是一致的,也就是說(shuō),和事務(wù)開始之前,數(shù)據(jù)存儲(chǔ)中的數(shù)據(jù)處于一致狀態(tài),保證數(shù)據(jù)的無(wú)損。以轉(zhuǎn)賬為例,假設(shè)用戶A和用戶B兩者的錢加起來(lái)一共是5000,那么不管A和B之間如何轉(zhuǎn)賬,轉(zhuǎn)幾次賬,事務(wù)結(jié)束后兩個(gè)用戶的錢相加起來(lái)應(yīng)該還是5000,這就是事務(wù)的一致性。
3. 隔離性(Isolation)隔離性是指事務(wù)與事務(wù)之間互相獨(dú)立,彼此隔離。當(dāng)多個(gè)用戶并發(fā)訪問數(shù)據(jù)庫(kù)時(shí),如操作同一張表,數(shù)據(jù)庫(kù)為每一個(gè)用戶開啟的事務(wù),不能被其他事務(wù)的操作所干擾。對(duì)于任意兩個(gè)并發(fā)的事務(wù)T1和T2,在事務(wù)T1看來(lái),T2要么在T1開始之前就已經(jīng)結(jié)束,要么在T1結(jié)束之后才開始,這樣每個(gè)事務(wù)都感覺不到有其他事務(wù)在并發(fā)地執(zhí)行。
關(guān)于事務(wù)的隔離性,數(shù)據(jù)庫(kù)提供了多種隔離級(jí)別,稍后會(huì)介紹。
4.持久性 (Durability)持久性是指事務(wù)一旦提交,那么對(duì)數(shù)據(jù)庫(kù)中的數(shù)據(jù)的改變就是永久性的,即使是數(shù)據(jù)庫(kù)系統(tǒng)遇到故障也不會(huì)丟失事務(wù)處理的效果。比如:銀行轉(zhuǎn)帳過(guò)程中,轉(zhuǎn)帳后帳戶的數(shù)據(jù)要能被永遠(yuǎn)地保存下來(lái)。
數(shù)據(jù)庫(kù)的隔離級(jí)別對(duì)數(shù)據(jù)庫(kù)而言,其明顯的特征是資源可以被多個(gè)用戶共享。當(dāng)相同的數(shù)據(jù)庫(kù)資源被多個(gè)用戶(多個(gè)事務(wù))同時(shí)訪問時(shí),如果沒有采取必要的隔離措施,就會(huì)導(dǎo)致各種并發(fā)問題,破壞數(shù)據(jù)的完整性。
如果不考慮隔離性,數(shù)據(jù)庫(kù)將會(huì)存在三種并發(fā)問題。
1.臟讀一個(gè)事務(wù)讀到了另一個(gè)事務(wù)尚未提交的更改數(shù)據(jù)。例如,事務(wù)T1修改某一數(shù)據(jù)后,事務(wù)T2讀取同一數(shù)據(jù),然后事務(wù)T1由于某種原因撤銷修改,這時(shí)T1已修改過(guò)的數(shù)據(jù)恢復(fù)原值,T2讀到的數(shù)據(jù)就與數(shù)據(jù)庫(kù)中的數(shù)據(jù)不一致,其讀到的數(shù)據(jù)就為"臟"數(shù)據(jù),對(duì)該數(shù)據(jù)的操作也無(wú)法承認(rèn)。
2.不可重復(fù)讀不可重復(fù)讀是指一個(gè)事務(wù)讀取數(shù)據(jù)后,另一個(gè)事務(wù)執(zhí)行更新操作,使第一個(gè)事務(wù)無(wú)法再現(xiàn)前一次的讀取結(jié)果。例如,事務(wù)T1讀取B=100進(jìn)行運(yùn)算,事務(wù)T2讀取同一數(shù)據(jù)B,對(duì)其進(jìn)行修改后將B=200寫回?cái)?shù)據(jù)庫(kù)。這時(shí),T1為了對(duì)讀取值校對(duì)重讀B,而B已為200,導(dǎo)致此次讀取值與第一次讀取值不一致。
3.幻讀幻讀是指一個(gè)事務(wù)讀取數(shù)據(jù)后,另一個(gè)事務(wù)執(zhí)行插入操作,使第一個(gè)事務(wù)無(wú)法再現(xiàn)前一次的讀取結(jié)果。例如,事務(wù)T1兩次統(tǒng)計(jì)所有賬戶的總金額,在這期間,事務(wù)T2插入了一條新記錄,使得兩次統(tǒng)計(jì)的總金額不一致。
為了解決并發(fā)造成的問題,數(shù)據(jù)庫(kù)規(guī)范定義了四種隔離級(jí)別,用于限定事務(wù)之間的可見性,不同的事務(wù)隔離級(jí)別對(duì)應(yīng)的解決數(shù)據(jù)并發(fā)問題的能力是不同的,具體如表2.1所示。
表2.1 數(shù)據(jù)庫(kù)的隔離級(jí)別
隔離級(jí)別 | 臟讀 | 不可重復(fù)讀 | 幻讀 |
read uncommitted (讀未提交) | 允許 | 允許 | 允許 |
read committed (讀已提交) | 不允許 | 允許 | 允許 |
repeatable read (可重復(fù)讀) | 不允許 | 不允許 | 允許 |
serializable (串行化) | 不允許 | 不允許 | 不允許 |
l read uncommitted (讀未提交):一個(gè)事務(wù)讀到另一個(gè)事務(wù)沒有提交的數(shù)據(jù)。
l read committed (讀已提交):一個(gè)事務(wù)讀到另一個(gè)事務(wù)已經(jīng)提交的數(shù)據(jù)。
l repeatable read (可重復(fù)讀):在一個(gè)事務(wù)中讀到的數(shù)據(jù)始終一致,無(wú)論其他事務(wù)是否提交。
l serializable(串行化):只能同時(shí)執(zhí)行一個(gè)事務(wù),相當(dāng)于事務(wù)中的單線程。
在以上四種隔離級(jí)別中,安全性最高的是serializable (串行化),最低的是read uncommitted(讀未提交),當(dāng)然安全性能越高,執(zhí)行效率就越低。像serializable(串行化)這樣的級(jí)別,就是以鎖表的方式,使得其他的事務(wù)只能在鎖外等待,所以平時(shí)選用何種隔離級(jí)別應(yīng)該根據(jù)實(shí)際情況。MySQL數(shù)據(jù)庫(kù)默認(rèn)的隔離級(jí)別為repeatable read (可重復(fù)讀)。
JDBC事務(wù)處理創(chuàng)建數(shù)據(jù)庫(kù)和表創(chuàng)建一個(gè)名稱為chapter02的數(shù)據(jù)庫(kù),并在該數(shù)據(jù)庫(kù)中創(chuàng)建名為account的表,向表中插入若干條數(shù)據(jù),具體的SQL語(yǔ)句如下。
上述SQL語(yǔ)句運(yùn)行完畢后,在命令行窗口檢驗(yàn)數(shù)據(jù)庫(kù)環(huán)境是否搭建成功,執(zhí)行select語(yǔ)句,執(zhí)行結(jié)果如下。
創(chuàng)建Java工程在Eclipse中新建Java工程chapter02,在工程chapter02下新建目錄lib,將MySQL數(shù)據(jù)庫(kù)的驅(qū)動(dòng)jar包mysql-connector-java-5.1.37-bin.jar復(fù)制到lib目錄下,右擊lib目錄下的mysql-connector-java-5.1.37-bin.jar,在彈出的菜單中選擇Build Path→Add to Build Path命令,完成jar包的導(dǎo)入。在工程chapter02的src目錄下新建com.qfedu.chapter02包,在com.qfedu.chapter02包下新建TestPayment類,該類用于模擬支付過(guò)程,其中,lilei將支付給shop人民幣100元,具體代碼如書中例2-1所示。
數(shù)據(jù)庫(kù)連接池數(shù)據(jù)庫(kù)連接池的必要性本書第1章已經(jīng)介紹過(guò),編寫JDBC程序一般會(huì)按照裝載數(shù)據(jù)庫(kù)驅(qū)動(dòng)、建立數(shù)據(jù)庫(kù)連接、執(zhí)行SQL語(yǔ)句、斷開數(shù)據(jù)庫(kù)連接的步驟進(jìn)行。
然而在實(shí)際開發(fā)過(guò)程中,建立連接是一個(gè)費(fèi)時(shí)的活動(dòng)。每一次請(qǐng)求都要建立一次數(shù)據(jù)庫(kù)連接,每次向數(shù)據(jù)庫(kù)建立連接的時(shí)候都要將 Connection 對(duì)象加載到內(nèi)存中,若遇到訪問量劇增的情況,勢(shì)必會(huì)造成系統(tǒng)資源和時(shí)間的大量消耗,嚴(yán)重的甚至?xí)斐煞?wù)器的崩潰。而且,對(duì)于每一次數(shù)據(jù)庫(kù)連接,使用完后都得斷開,數(shù)據(jù)庫(kù)的連接資源不能得到很好的重復(fù)利用。如果程序出現(xiàn)異常而未能關(guān)閉連接,將會(huì)導(dǎo)致數(shù)據(jù)庫(kù)系統(tǒng)中的內(nèi)存泄漏,最終導(dǎo)致重啟數(shù)據(jù)庫(kù)。
從以上分析可以看出,傳統(tǒng)的管理數(shù)據(jù)庫(kù)連接的方式存在缺陷,為了解決這個(gè)問題,在實(shí)際開發(fā)中通常使用數(shù)據(jù)庫(kù)連接池技術(shù)。
數(shù)據(jù)庫(kù)連接池數(shù)據(jù)庫(kù)連接池,簡(jiǎn)單的說(shuō),就是為數(shù)據(jù)庫(kù)連接建立一個(gè)“緩沖池”。預(yù)先在緩沖池中放入一定數(shù)量的連接,當(dāng)需要建立數(shù)據(jù)庫(kù)連接時(shí),只需從“緩沖池”中取出一個(gè),使用完畢之后再放回去,具體如圖2.1所示。
圖2.1 數(shù)據(jù)庫(kù)連接池
數(shù)據(jù)庫(kù)連接池負(fù)責(zé)分配、管理和釋放數(shù)據(jù)庫(kù)連接,它允許應(yīng)用程序重復(fù)使用一個(gè)現(xiàn)有的數(shù)據(jù)庫(kù)連接,而不是重新建立一個(gè)。數(shù)據(jù)庫(kù)連接池對(duì)連接資源進(jìn)行管理和調(diào)配,共有四個(gè)方面的優(yōu)勢(shì)。
1. 資源重用由于數(shù)據(jù)庫(kù)連接得到重用,避免了頻繁創(chuàng)建、釋放連接引起的大量性能開銷。在減少系統(tǒng)消耗的基礎(chǔ)上,也增進(jìn)了系統(tǒng)運(yùn)行環(huán)境的平穩(wěn)性,減少內(nèi)存碎片以及數(shù)據(jù)庫(kù)臨時(shí)進(jìn)程/線程的數(shù)量。
2. 更快的系統(tǒng)響應(yīng)速度數(shù)據(jù)庫(kù)連接池在初始化過(guò)程中,往往已經(jīng)創(chuàng)建了若干數(shù)據(jù)庫(kù)連接置于池中備用。此時(shí)連接的初始化工作均已完成。對(duì)于業(yè)務(wù)請(qǐng)求處理而言,直接利用現(xiàn)有可用連接,避免了數(shù)據(jù)庫(kù)連接初始化和釋放過(guò)程的時(shí)間開銷,從而縮減了系統(tǒng)整體響應(yīng)時(shí)間。
3. 新的資源分配手段對(duì)于多程序共享同一數(shù)據(jù)庫(kù)的系統(tǒng),可在應(yīng)用層通過(guò)數(shù)據(jù)庫(kù)連接池配置某一程序能夠使用的最大數(shù)據(jù)庫(kù)連接數(shù),避免某一程序獨(dú)占所有數(shù)據(jù)庫(kù)資源。
4. 統(tǒng)一的連接管理,避免數(shù)據(jù)庫(kù)連接泄漏在較為完備的數(shù)據(jù)庫(kù)連接池的實(shí)現(xiàn)中,可根據(jù)預(yù)先的連接占用超時(shí)設(shè)定,強(qiáng)制收回被占用的連接,從而避免了常規(guī)數(shù)據(jù)庫(kù)在連接操作中可能出現(xiàn)的資源泄漏。
數(shù)據(jù)庫(kù)連接池工作原理連接池技術(shù)的核心思想是連接的復(fù)用,通過(guò)建立一個(gè)數(shù)據(jù)庫(kù)連接池以及一套連接使用、分配、管理策略,使得該連接池中的連接可以得到高效、安全的復(fù)用,避免了數(shù)據(jù)庫(kù)連接頻繁建立、關(guān)閉的開銷。另外,由于對(duì)JDBC中的原始連接進(jìn)行了封裝,從而方便了數(shù)據(jù)庫(kù)應(yīng)用對(duì)于連接的使用,提高了開發(fā)效率。
對(duì)連接池的工作原理可以從連接池的建立、連接池的管理、連接池的關(guān)閉、連接池的配置四個(gè)方面去理解。
1. 連接池的建立一般在系統(tǒng)初始化時(shí),連接池會(huì)根據(jù)系統(tǒng)配置建立,并在池中建立若干個(gè)連接對(duì)象,以便使用時(shí)能從連接池中獲取。為避免連接隨意建立和關(guān)閉造成的系統(tǒng)開銷,連接池中的連接不能隨意創(chuàng)建和關(guān)閉。Java中提供了很多容器類,可以方便地構(gòu)建連接池。
2. 連接池的管理
連接池管理策略是連接池機(jī)制的核心,會(huì)對(duì)系統(tǒng)性能產(chǎn)生很大影響。當(dāng)線程請(qǐng)求數(shù)據(jù)庫(kù)連接時(shí),首先查看連接池中是否有空閑連接,如果存在空閑連接,則將連接分配給線程使用。如果沒有空閑連接,則查看當(dāng)前所開的連接數(shù)是否已經(jīng)達(dá)到最杭州接數(shù),如果沒有達(dá)到就重新創(chuàng)建一個(gè)連接;如果達(dá)到,就按設(shè)定的最大等待時(shí)間進(jìn)行等待,如果超出最大等待時(shí)間,則拋出異常。
當(dāng)線程釋放數(shù)據(jù)庫(kù)連接時(shí),先判斷該連接的引用次數(shù)是否超過(guò)了規(guī)定值,如果超過(guò)了就從連接池中刪除該連接,否則就保留為其他線程服務(wù)。該策略保證了數(shù)據(jù)庫(kù)連接的有效復(fù)用,避免了頻繁建立釋放連接所帶來(lái)的系統(tǒng)資源開銷。
3. 連接池的關(guān)閉當(dāng)應(yīng)用程序退出時(shí),關(guān)閉連接池中所有的鏈接,釋放連接池相關(guān)資源,該過(guò)程正好與創(chuàng)建相反。
4. 連接池的配置數(shù)據(jù)庫(kù)連接池中采用minConn和maxConn來(lái)限制連接的數(shù)量。minConn是當(dāng)應(yīng)用啟動(dòng)時(shí)連接池所創(chuàng)建的連接數(shù),如果過(guò)大啟動(dòng)將變慢,但是啟動(dòng)后響應(yīng)更快;如果過(guò)小啟動(dòng)將加快,但是最初使用時(shí)會(huì)因?yàn)檫B接不足而延緩執(zhí)行速度,可以通過(guò)反復(fù)試驗(yàn)來(lái)確定飽和點(diǎn)。maxConn是連接池中的最杭州接數(shù),設(shè)定連接池最杭州接數(shù)來(lái)防止系統(tǒng)無(wú)盡的與數(shù)據(jù)庫(kù)連接。
自定義數(shù)據(jù)庫(kù)連接池為了方便大家理解,本書將演示如何自定義一個(gè)簡(jiǎn)單的連接池。自定義連接池,基本思想就是新建一個(gè)List集合充當(dāng)連接池,然后在連接池中添加幾個(gè)連接,當(dāng)使用連接的時(shí)候,從連接池中獲取,當(dāng)不使用時(shí),將連接歸還到連接池中。
(1)在src目錄下的com.qfedu.chapter02包下新建MyConnectionPool類,該類用于模擬連接池的基本功能,具體代碼如例2.2所示。
(2)在src目錄下的com.qfedu.chapter02包下新建TestMyConnectionPool類,該類用于測(cè)試連接池的效果,具體代碼如例2.3所示。
實(shí)際開發(fā)中已有很多性能優(yōu)良的第三方連接池可供使用,開發(fā)者一般只需理解連接池的原理,如果沒有特殊要求就無(wú)須自行定義連接池。
為了方便地利用數(shù)據(jù)庫(kù)連接池進(jìn)行開發(fā),Java語(yǔ)言為數(shù)據(jù)庫(kù)連接池提供了公共的接口DataSource,第三方數(shù)據(jù)庫(kù)連接池一般都要實(shí)現(xiàn)該接口,從而使Java程序能夠在不同的數(shù)據(jù)庫(kù)連接池之間切換。
目前常用的數(shù)據(jù)庫(kù)連接池 C3P0和DBCP,它們都是實(shí)現(xiàn)DataSource接口的。接下來(lái),本書將對(duì)這兩種數(shù)據(jù)庫(kù)連接池作重點(diǎn)講解。
C3P0數(shù)據(jù)庫(kù)連接池C3P0數(shù)據(jù)庫(kù)連接池介紹在目前的開發(fā)中,C3P0是使用較多的開源數(shù)據(jù)庫(kù)連接池之一,它性能高效,支持JDBC定義的規(guī)范,擴(kuò)展性好,可以和Hibernate、Spring等開源框架整合使用,很受開發(fā)者歡迎。
C3P0數(shù)據(jù)庫(kù)連接池通過(guò)核心類ComboPooledDataSource實(shí)現(xiàn)DataSource接口,該類支撐著整個(gè)連接池的主要功能。它提供了充足的方法來(lái)實(shí)現(xiàn)對(duì)數(shù)據(jù)庫(kù)連接池的配置和操作,具體如表2.2所示。
表2.2 ComboPooledDataSource類的方法
方法名稱 | 功能描述 |
void setDriverClass(String driverClass) | 設(shè)置連接數(shù)據(jù)庫(kù)的驅(qū)動(dòng) |
void setJdbcUrl(String jdbcUrl) | 設(shè)置連接數(shù)據(jù)庫(kù)的路徑 |
void setUser(String user) | 設(shè)置數(shù)據(jù)庫(kù)用戶名 |
void setPassword(String password) | 設(shè)置數(shù)據(jù)庫(kù)密碼 |
void setMaxPoolSize(int maxPoolSize) | 設(shè)置數(shù)據(jù)庫(kù)連接池最杭州接數(shù) |
void setMinPoolSize(int minPoolSize) | 設(shè)置數(shù)據(jù)庫(kù)連接池最小連接數(shù) |
void setInitialPoolSize(int initialPoolSize) | 設(shè)置數(shù)據(jù)庫(kù)連接池初始化的連接數(shù) |
void setMaxIdleTime(int maxIdleTime) | 設(shè)置連接的最大空閑時(shí)間 |
Connection getConnection() | 獲得連接 |
C3P0數(shù)據(jù)庫(kù)連接池使用使用C3P0數(shù)據(jù)庫(kù),主要是對(duì)其核心類ComboPooledDataSource方法的調(diào)用,在此之前,首先要獲得一個(gè)可用的ComboPooledDataSource對(duì)象。通常情況下,獲得該對(duì)象的方法有兩種。
1. 直接創(chuàng)建ComboPooledDataSource對(duì)象并設(shè)置屬性這種實(shí)現(xiàn)方式使用ComboPooledDataSource類直接創(chuàng)建對(duì)象,然后調(diào)用方法為其設(shè)置屬性,最后獲取數(shù)據(jù)庫(kù)的連接,接下來(lái)將通過(guò)具體實(shí)例對(duì)這一過(guò)程進(jìn)行講解。
(1)將C3P0連接池的jar包c(diǎn)3p0-0.9.2-pre5.jar和mchange-commons-java-0.2.3.jar復(fù)制到工程chapter02的lib目錄下,右擊lib目錄下的上述jar包,在彈出的菜單中選擇Build Path→Add to Build Path,完成jar包的導(dǎo)入。
(2)在src目錄下的com.qfedu.chapter02包下新建TestC3P0_1類,具體代碼如例2.4所示。
2. 通過(guò)讀取配置文件創(chuàng)建ComboPooledDataSource對(duì)象使用這種方式,首先將數(shù)據(jù)庫(kù)連接池的配置信息寫入了c3p0-config.xml文件中,然后通過(guò)ComboPooledDataSource類的構(gòu)造方法讀取配置信息并創(chuàng)建該類對(duì)象,最后調(diào)用該類對(duì)象的方法獲取數(shù)據(jù)庫(kù)連接,接下來(lái)將通過(guò)具體實(shí)例對(duì)這一過(guò)程進(jìn)行講解。
(1)在src目錄下創(chuàng)建一個(gè)c3p0-config.xml的配置文件,具體代碼如例2.5所示。
在c3p0-config.xml文件中,<default-config>……</default-config>標(biāo)簽中的內(nèi)容為默認(rèn)配置,如果在創(chuàng)建ComboPooledDataSource對(duì)象時(shí)沒有指定配置信息,就默認(rèn)采用該配置。<named-config name="qfedu">……</named-config>標(biāo)簽中的內(nèi)容為命名配置,如果想要采用該配置,就必須在需要在創(chuàng)建ComboPooledDataSource對(duì)象時(shí)傳入<named-config>標(biāo)簽中name屬性的值。
(2)在src目錄下的com.qfedu.chapter02包下新建TestC3P0_2類,該類用于測(cè)試C3P0數(shù)據(jù)庫(kù)連接池的功能。
DBCP數(shù)據(jù)庫(kù)連接池DBCP數(shù)據(jù)庫(kù)連接池介紹DBCP是數(shù)據(jù)庫(kù)連接池(DataBase connection pool)的簡(jiǎn)稱,是由Apache組織開發(fā)的開源數(shù)據(jù)庫(kù)連接池。該連接池既可以與應(yīng)用服務(wù)器整合使用,也可由應(yīng)用程序獨(dú)立使用。Tomcat服務(wù)器即內(nèi)置了該數(shù)據(jù)庫(kù)連接池。
DBCP數(shù)據(jù)庫(kù)連接池通過(guò)BasicDataSource核心類實(shí)現(xiàn)DataSource接口,與C3P0連接池的CombopooledDataSource類相同,BasicDataSource類也提供了一套API來(lái)完成對(duì)連接池對(duì)象的配置和操作。BasicDataSource類提供的方法如表2.3所示
表2.3 BasicDataSource類的方法
方法名稱 | 功能描述 |
void setDriverClassName(String driverClassName) | 設(shè)置連接數(shù)據(jù)庫(kù)的驅(qū)動(dòng) |
void setUrl(String url) | 設(shè)置連接數(shù)據(jù)庫(kù)的路徑 |
void setUsername(String username) | 設(shè)置數(shù)據(jù)庫(kù)用戶名 |
void setPassword(String password) | 設(shè)置數(shù)據(jù)庫(kù)密碼 |
void setMaxActive(int maxActive) | 設(shè)置數(shù)據(jù)庫(kù)連接池最杭州接數(shù) |
void setMinIdle(int minIdle) | 設(shè)置數(shù)據(jù)庫(kù)連接池最小連接數(shù) |
void setInitialSize(int initialSize) | 設(shè)置數(shù)據(jù)庫(kù)連接池初始化的連接數(shù) |
Connection getConnection() | 獲得連接 |
除了BasicDataSource類,DBCP數(shù)據(jù)庫(kù)連接池還提供了BasicDataSourceFactory類用于創(chuàng)建BasicDataSource對(duì)象,它通過(guò)調(diào)用createDataSource()方法讀取配置文件信息并返回一個(gè)連接池對(duì)象給調(diào)用者,這些與C3P0是不同的。
DBCP數(shù)據(jù)庫(kù)連接池的使用當(dāng)使用DBCP數(shù)據(jù)庫(kù)連接池時(shí),首先要獲取BasicDataSource對(duì)象。獲取BasicDataSourc對(duì)象有兩種方法,具體如下。
1.直接創(chuàng)建BasicDataSource并設(shè)置屬性這種實(shí)現(xiàn)方式采用硬編碼方式,直接創(chuàng)建ComboPooledDataSource對(duì)象后調(diào)用方法為其設(shè)置屬性值,最后獲取數(shù)據(jù)庫(kù)的連接。
2. 通過(guò)讀取配置文件創(chuàng)建ComboPooledDataSource對(duì)象使用這種方式,首先將數(shù)據(jù)庫(kù)連接池的配置信息寫入dbcpconfig.properties文件中,然后通過(guò)BasicDataSourceFactory類讀取配置信息并創(chuàng)建BasicDataSource對(duì)象,最后調(diào)用該對(duì)象的方法獲取數(shù)據(jù)庫(kù)連接。
小結(jié):Java Web開發(fā)實(shí)戰(zhàn)—JDBC進(jìn)階本章主要介紹了JDBC事務(wù)處理以及數(shù)據(jù)庫(kù)連接池的相關(guān)知識(shí),包括事務(wù)的概念、屬性,JDBC事務(wù)處理,數(shù)據(jù)庫(kù)連接池的概述以及工作原理等,最后通過(guò)案例對(duì)C3P0和DBCP兩種數(shù)據(jù)庫(kù)連接池技術(shù)進(jìn)行了詳細(xì)講解。通過(guò)對(duì)本章內(nèi)容的學(xué)習(xí),大家應(yīng)該掌握J(rèn)DBC處理事務(wù)以及通過(guò)數(shù)據(jù)庫(kù)連接池獲取連接的開發(fā)流程。