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