劉冰 潘大兵 楊輝
摘 ?;要: 在開發(fā)基于Java的應(yīng)用時,提高對數(shù)據(jù)庫的訪問效率是程序員重點要考慮的問題之一。研究、分析了Java通過JDBC訪問數(shù)據(jù)庫的四種訪問類型,提出了在不同的使用過程中的選擇方案。介紹了連接池等對數(shù)據(jù)庫訪問效率影響較大的預(yù)處理語句及數(shù)據(jù)庫連接管理技術(shù)。探討了當(dāng)前使用最為普遍的Hibernate在配置連接池和使用緩存等方面的問題。
關(guān)鍵詞: JDBC驅(qū)動程序; 連接池; 預(yù)處理; 緩存
中圖分類號:TP39 ?; ?; ?; ?; ?;文獻(xiàn)標(biāo)志碼:A ?; ?; 文章編號:1006-8228(2014)12-05-03
Research on promoting efficiency of database on Java
Liu Bing, Pan Dabing, Yang Hui
(Dazhou vocational and technical college, Dazhou, Sichuan 635001, China)
Abstract: One of the most important questions for a programmer to meditate is how to improve the visiting efficiency of database when developing an application based on Java. After researching and analyzing fourvisiting types of Javato database by JDBC,different projects to choose in diverse situations are put forward. Pre-statement which will greatly affect the visiting efficiency, such as connection pool, and database connection management technology are introduced. The problems which are related to the use of Hibernate in connection pool and the cache usage are also briefly discussed in this article.
Key words: JDBC driver; connection pool; pre-statement; cache
0 引言
Java語言具有與系統(tǒng)平臺無關(guān)、安全、穩(wěn)定、易于使用和易于從網(wǎng)絡(luò)上下載等特性,它不僅可以用來開發(fā)大型的應(yīng)用程序,而且特別適合于Web應(yīng)用的開發(fā)。Java技術(shù)的核心之一就是對數(shù)據(jù)庫的訪問,SUN公司為此提供了一種標(biāo)準(zhǔn)的SQL訪問數(shù)據(jù)庫的編程接口JDBC,用來支持對各種平臺的數(shù)據(jù)庫進(jìn)行訪問。
本文介紹了各種JDBC訪問類型,在對它們進(jìn)行分析、比較的基礎(chǔ)上提出一個在使用過程中的選擇建議;對通過JDBC建立數(shù)據(jù)庫的連接提出了一個高效建立和管理的策略——連接池技術(shù)。另外,在對向數(shù)據(jù)庫服務(wù)器發(fā)送SQL語句的過程中,對于如何使用Statement接口和PreparedStatement接口給出了一個選擇建議;就當(dāng)前常用的Hibernate技術(shù)在連接池和緩存等方面的使用作了相應(yīng)介紹。
1 Java數(shù)據(jù)庫訪問機制
JDBC是一種用于執(zhí)行SQL語句的Java API,是Java數(shù)據(jù)庫連接技術(shù)的簡稱。一般JDBC有兩層接口:驅(qū)動程序?qū)雍蛻?yīng)用程序?qū)?。前者?fù)責(zé)處理與具體驅(qū)動程序版本的所有通信,后者用于開發(fā)人員通過SQL調(diào)用數(shù)據(jù)庫和取得結(jié)果。
在驅(qū)動程序?qū)又杏兴姆N類型的驅(qū)動程序:①JDBC-ODBC橋驅(qū)動程序;②本地API驅(qū)動程序;③純Java的網(wǎng)絡(luò)協(xié)議驅(qū)動程序;④純Java的本地協(xié)議驅(qū)動程序[7]。
在應(yīng)用程序?qū)又杏兴姆N重要的接口:①Java.sql.DriverManager,用于處理驅(qū)動程序的裝載和建立新的數(shù)據(jù)庫連接;②Java.sql.Connection,用于完成對某一指定數(shù)據(jù)庫的連接;③Java.sql-Statement,用于管理在指定數(shù)據(jù)庫連接上的SQL語句的執(zhí)行;④Java.sql.ResultSet,用于從數(shù)據(jù)庫返回結(jié)果集。
2 提高數(shù)據(jù)庫訪問效率的策略
2.1 選擇合適的JDBC驅(qū)動程序
下面將對驅(qū)動程序?qū)又械乃姆N類型的驅(qū)動程序在訪問數(shù)據(jù)庫方面的優(yōu)劣進(jìn)行分析、比較,在此在基礎(chǔ)上給出一個相應(yīng)的選擇建議。
⑴ JDBC-ODBC橋驅(qū)動程序:由于通常的DBMS都支持微軟提出的ODBC規(guī)范,同時,它的配置也相當(dāng)簡單,因此這一機制可作為在具體應(yīng)用開發(fā)中的一個選擇。但這種方法有它的不足,即:其執(zhí)行效率較低,對于大數(shù)據(jù)量存取的應(yīng)用是不太適合的;它還要求客戶端必須安裝ODBC驅(qū)動,這顯然也不適合于遠(yuǎn)程的數(shù)數(shù)據(jù)庫訪問。
⑵ 本地API驅(qū)動程序:它是其他三者利弊平衡的妥協(xié)產(chǎn)物。與類型一相比較,它借鑒了其利用客戶端的本地代碼庫,加速了數(shù)據(jù)訪問的執(zhí)行,但卻摒除了ODBC標(biāo)準(zhǔn),而是支持廠商自己指定的性能擴(kuò)展;與類型三相比較,它利用其多層的結(jié)構(gòu),即上層用Java實現(xiàn),以利于跨平臺應(yīng)用和支持多數(shù)據(jù)庫,下層改為本地代碼,以利于加速執(zhí)行的速度;與類型四相比較,借鑒了其與數(shù)據(jù)庫結(jié)合緊密的優(yōu)點,其相當(dāng)一部分用Java實現(xiàn),這對數(shù)據(jù)庫性能有了很大的提升。這種類型的效率比起類型一來說雖然要高一些,但仍然需要在每臺客戶端上預(yù)先安裝本地API庫,因此不利于維護(hù)和使用。
⑶ 純Java的網(wǎng)絡(luò)協(xié)議驅(qū)動程序:在大型的企業(yè)級的應(yīng)用中,后臺的數(shù)據(jù)庫往往不只一個,而且一般又是由不同的廠商支持。而該類型的驅(qū)動程序恰恰提供了對多種數(shù)據(jù)庫的支持,與類型四相比,體現(xiàn)了它的靈活性優(yōu)勢。同時,該類型的驅(qū)動程序一般還提供了許多企業(yè)級的特征,例如SSL安全、支持分布式事務(wù)處理和集中管理等,這在實現(xiàn)某些特殊的用途方面將會帶來一定的幫助。是否選用,要根據(jù)其應(yīng)用本身是否需要對多DBMS的支持和某些擴(kuò)展應(yīng)用的需求。比較而言,這類驅(qū)動程序的體積最小、效率較高,具有最大的靈活性,其缺點是需要一個中間服務(wù)器的支持。另外,此類驅(qū)動程序采用標(biāo)準(zhǔn)的網(wǎng)絡(luò)協(xié)議,可以被防火墻支持,是Internet應(yīng)用理想的解決方案。
⑷ 純Java的本地協(xié)議驅(qū)動程序:就當(dāng)前一些主流DBMS的提供者來說,它們往往會為自己的數(shù)據(jù)庫提供一個應(yīng)用該類型驅(qū)動程序的JDBC接口。這種類型的驅(qū)動程序優(yōu)勢在于它和數(shù)據(jù)庫本身結(jié)合比較緊密,而且是純Java的實現(xiàn),在企業(yè)級應(yīng)用中,應(yīng)該是首選。例如,對于Oracle數(shù)據(jù)庫來說,Oracle、SilverStream、DataDirect等公司都提供了這種類型的驅(qū)動,就目前各種測試數(shù)據(jù)來看,該類型驅(qū)動程序的性能往往被評價為最高的和最可靠的,同時,其訪問數(shù)據(jù)庫的效率也有不錯的表現(xiàn)。但由于其采用DBMS專用的網(wǎng)絡(luò)協(xié)議,可能不被防火墻支持,在Internet應(yīng)用中也會存在潛在安全隱患[8]。
通過上述分析、比較,我們用一個表來對這四種類型的驅(qū)動程序在不同情況下的選擇順序作一總結(jié),如表1。
表1 ?;JDBC驅(qū)動程序選擇建議方案
2.2 使用連接池
在Java應(yīng)用程序訪問數(shù)據(jù)庫的模式的步驟二中,需要通過JDBC來建立數(shù)據(jù)庫連接,對連接的管理又往往是決定應(yīng)用性能的一個重要因素。當(dāng)前,對于連接的管理的最為有效的策略是使用連接池技術(shù)。
連接池的思想是:Web服務(wù)器可以事先預(yù)備好若干個連接對象,將這些連接對象存放在一個稱為連接池的容器中,當(dāng)某用戶需要操作數(shù)據(jù)庫時,只要從連接池中取出一個連接對象即可,當(dāng)用戶使用完該連接對象后,將該連接對象放回到連接池中。如果某用戶需要操作數(shù)據(jù)庫時,連接池中已沒有連接對象可用,那么該用戶就必須等待,直到連接池中有了連接對象[1]。
在應(yīng)用程序中可以使用Java為我們提供的某些容器類(諸如:Vector、Stack等)來方便地構(gòu)建連接池。在實際實現(xiàn)中,通常是將數(shù)據(jù)庫連接作為一個對象存儲在這些容器類對象中(即連接池)。
當(dāng)連接池創(chuàng)建好后,若在連接池中設(shè)有空閑隊列和已分配隊列,則空閑隊列存放未分配的連接,已分配隊列存放正在使用的連接。當(dāng)客戶應(yīng)用連接池請求數(shù)據(jù)庫連接時,先查看池中有沒有被分配的空閑連接,如果存在空閑連接則把空閑連接分配給客戶,并作相應(yīng)處理,主要的處理策略就是設(shè)置該連接為已使用即分配狀態(tài),即注冊到已分配隊列中。若連接池中沒有空閑連接,則先看該連接池是否已達(dá)到最大連接數(shù),若未達(dá)到則創(chuàng)建新連接并設(shè)置其為已分配狀態(tài)即可,若已達(dá)到最大連接數(shù)則只能等待其他線程釋放連接后才能獲取,若超過允許的最大等待時間則此次請求無效。當(dāng)客戶釋放連接時,應(yīng)喚醒所有等待連接的客戶線程并做相應(yīng)的處理。如果連接釋放后沒有等待連接的客戶線程,則把它重新放回連接池的空閑隊列中,但并不關(guān)閉該連接[2]。
由于數(shù)據(jù)庫連接池在初始化過程中,往往已經(jīng)創(chuàng)建了若干數(shù)據(jù)庫連接置于池中備用。此時連接的初始化工作均已完成。對于業(yè)務(wù)請求處理而言,直接利用現(xiàn)有可用連接,可避免數(shù)據(jù)庫連接初始化和釋放過程的時間開銷,從而縮減了系統(tǒng)整體響應(yīng)時間。
另外,數(shù)據(jù)庫連接能夠得到重用,避免了頻繁創(chuàng)建、釋放連接引起的大量性能開銷。在減少系統(tǒng)消耗的基礎(chǔ)上也增強了系統(tǒng)運行環(huán)境的平穩(wěn)性(減少內(nèi)存碎片以及數(shù)據(jù)庫臨時進(jìn)程/線程的數(shù)量)。在較為完備的數(shù)據(jù)庫連接池實現(xiàn)中,還可根據(jù)預(yù)先的連接占用超時設(shè)定,強制收回被占用連接,從而避免了常規(guī)數(shù)據(jù)庫連接操作中可能出現(xiàn)的資源泄漏。
2.3 使用預(yù)處理
Java提供了高效率的數(shù)據(jù)庫操作機制,這就是PreparedStatement對象,該對象被習(xí)慣性地稱為預(yù)處理語句對象。
當(dāng)向數(shù)據(jù)庫發(fā)送一個SQL語句,比如Select*From employee,數(shù)據(jù)庫庫中的SQL解釋器負(fù)責(zé)將SQL語句生成底層的內(nèi)部命令,然后執(zhí)行該命令,完成有關(guān)的數(shù)據(jù)操作。如果不斷地向數(shù)據(jù)庫提交SQL語句,勢必增加數(shù)據(jù)庫中SQL解釋器的負(fù)擔(dān),影響執(zhí)行速度。如果應(yīng)用程序能針對連接的數(shù)據(jù)庫,事先就將SQL語句解釋為數(shù)據(jù)庫底層的內(nèi)部命令,然后直接由主數(shù)據(jù)庫去執(zhí)行這個命令,顯然不僅能減輕數(shù)據(jù)庫的負(fù)擔(dān),而且也能提高訪問數(shù)據(jù)庫的速度。
對于JDBC,如果使用Connection 和某個數(shù)據(jù)庫建立了連接對象con,那么con就可以調(diào)用prepareStatement(String sql)方法對參數(shù)sql指定的SQL語句進(jìn)行預(yù)編譯處理,生成該數(shù)據(jù)庫底層的內(nèi)部命令,并將該命令封裝在PrepareStatement對象中,那么該對象調(diào)用下列方法都可以使得該底層內(nèi)部命令被數(shù)據(jù)庫執(zhí)行:
ResultSet executeQuery()
boolean execute()
int executeUpdate()
只要編譯好了PrepareStatement對象,那么該對象可以隨時執(zhí)行上述方法,顯然提高了訪問數(shù)據(jù)庫的速度。
2.4 使用Hibernate
Hibernate是基于Java的開源持久化中間件,它對JDBC實現(xiàn)了輕量級的封裝。開發(fā)人員通過Hibernate提供的API可以很輕松地操作數(shù)據(jù)庫。Hibernate可以應(yīng)用在任何使用JDBC的場合,既可以在Java的客戶端程序使用,也可以在Java Web應(yīng)用中使用,完成數(shù)據(jù)持久化的重任。
但是在很多情況下Hibernate的性能比直接使用JDBC存取數(shù)據(jù)庫要低,這是因為Hibernate的底層實現(xiàn)是通過JNDI(Java命名與目錄接口)、JDBC、JTA(Java事務(wù)API)來實現(xiàn)的,Hibernate做的是持久化封裝,無論封裝有多高效,也沒有直接操作JDBC效率高[6]。
然而,通過正確的方法和策略,在使用Hibernate的時候還是可以非常接近直接使用JDBC時的效率的,并且,在有些情況下還有可能高于使用JDBC時的執(zhí)行效率。
在進(jìn)行Hibernate性能優(yōu)化時,需要考慮的方面較多,其中連接池的配置和緩存的使用是最為主要的方面。
⑴ 連接池的配置
在Hibernate中配置連接池的方式有以下三種。
方式1:使用Hibernate自帶的連接池。
方式2:使用配置文件指定的數(shù)據(jù)庫連接池。
方式3:從容器中獲取得到連接池(如:Tomcat)。
Hibernate無論采用哪種方式獲取連接池的連接,它對Java程序來說是獨立的。Hibernate對其采用了配置化處理,也就是當(dāng)想改變獲取數(shù)據(jù)庫連接的方式時,只要修改Hibernate的配置文件就可以了。
① 使用Hibernate自帶的連接池
Hibernate自帶的連接池性能不高,缺乏響應(yīng)大批量請求以及容錯能力,甚至還有BUG,在項目運用中不值得推薦。限地篇幅,本文對其配置方法不作介紹。
② 使用配置文件指定的連接池
筆者在這里推薦當(dāng)今穩(wěn)定而且主流的數(shù)據(jù)源,就是Hibernate支持的第三方連接池產(chǎn)品:C3P0,Proxool。
③ 從容器中獲取得到連接池(如:Tomcat)
Hibernate想要從Tomcat中獲取數(shù)據(jù)源,需要對Tomcat容器與Hibernate分別進(jìn)行配置[6]。
⑵ 使用緩存
對于Hibernate這類ORM(Object Relation Mapping)而言,緩存就顯得尤為重要,它是持久層性能提升的關(guān)鍵。雖然Hibernate通過對JDBC的封裝來實現(xiàn)了內(nèi)部狀態(tài)的管理、OR(Object Relation)關(guān)系的映射等,但隨之帶來的就是數(shù)據(jù)訪問效率的降低和系統(tǒng)性能的下降,而緩存正是彌補這一缺點的重要方法。
在Hibernate中主要有三種不同的緩存:一級緩存、二級緩存和查詢緩存。一級緩存在Hibernate中對應(yīng)的是session范圍的緩存,也就是當(dāng)session關(guān)閉時緩存即被清除,一級緩存在Hibernate中是不可配置的部分;二級緩存在Hibernate中對應(yīng)的是SessionFactory范圍的緩存,通常來講SessionFactory的生命周期和應(yīng)用的生命周期相同,二級緩存在Hibernate中是可以配置的,可以通過class-cache配置類粒度級別的緩存,同時也可通過collection-cache配置集合粒度級別的緩存;查詢緩存在Hibernate同樣是可配置的,默認(rèn)是關(guān)閉的,可以通過設(shè)置cache.use_query_cache為true來打開查詢緩存。
緩存的實現(xiàn)通常是通過key/value的Map方式來實現(xiàn),在Hibernate的一級、二級和查詢緩存也同樣如此。一級、二級緩存使用的key均為po的主鍵ID,value即為po實例對象,查詢緩存使用的則是查詢的條件、查詢的參數(shù)、查詢的頁數(shù)。value有兩種情況,如果采用的是select po.property這樣的方式,那么value為整個結(jié)果集,如采用的是from這樣的方式,那么value為獲取的結(jié)果集中各po對象的主鍵ID[6]。
3 結(jié)束語
就Java應(yīng)用開發(fā)而言,恰當(dāng)?shù)剡x擇JDBC驅(qū)動程序、使用連接池、對SQL語句進(jìn)行預(yù)處理和使用Hibernate中的相關(guān)API等是提高數(shù)據(jù)庫訪問效率的一些主要解決方案。就軟件技術(shù)而言,除本文提到的方法以外,在某些應(yīng)用中,使用JavaBean技術(shù)、線程技術(shù)、優(yōu)化查詢語言和恰當(dāng)?shù)乩檬聞?wù)處理等也能夠在一定程度上提升數(shù)據(jù)庫的訪問效率。此外,硬件設(shè)備的改善無疑是一個重要方面。因此,合理地選擇及整合相關(guān)的技術(shù)方案,并結(jié)合實際開發(fā)環(huán)境,才可能夠在更大的程度上提高數(shù)據(jù)庫的訪問效率。
受篇幅所限,本文沒能詳細(xì)地給出相關(guān)技術(shù)的具體設(shè)計與實現(xiàn)。作者旨在通過本文的研究使讀者能從宏觀層面把握相關(guān)技術(shù),并能由此及彼展開對相關(guān)問題的探討,以期獲得最優(yōu)的解決方案。
參考文獻(xiàn):
[1] 孫葉楓,宋中山.JSP中基于連接池的數(shù)據(jù)庫訪問技術(shù)[J].計算機應(yīng)
用,2004.6:80-82
[2] 黃偉.在JSP中使用連接池優(yōu)化數(shù)據(jù)庫訪問效率[J].計算機應(yīng)用,
2002.4:67-70
[3] 耿祥義,張躍平.Java 2實用教程(第三版)[M].清華大學(xué)出版社,2006.
[4] 黃文,謝寄石.基于J2EE的數(shù)據(jù)庫連接服務(wù)[J].電子科技大學(xué)學(xué)報,
2002.1:67-71
[5] (美)埃史爾.Java編程思想(第4版)[M].機械工業(yè)出版社,2007.
[6] 付京周.精通Hibernate 3.0[M].人民郵電出版社,2007.
[7] 張曉東.Java數(shù)據(jù)庫高級教程[M].清華大學(xué)出版社,2004.
[8] (美)霍斯特曼.JAVA核心技術(shù)卷II[M].機械工業(yè)出版社,2008.
[9] 汪曉平,賈敬習(xí),李功.精通Java網(wǎng)絡(luò)編程(第二版)[M].清華大學(xué)出版
社,2009.
[10] 孫衛(wèi)琴.Java網(wǎng)絡(luò)編程精解[M].電子工業(yè)出版社,2007.