文|戴長秀
提高Java訪問數(shù)據(jù)庫效率的方法研究與探討
文|戴長秀
隨著“互聯(lián)網(wǎng)+”時代的到來,互聯(lián)網(wǎng)應(yīng)用已深入各行各業(yè),電子商務(wù)發(fā)展態(tài)勢尤為突出。信息技術(shù)和網(wǎng)絡(luò)技術(shù)發(fā)展迅速,導(dǎo)致信息量和數(shù)據(jù)量猛增,怎樣才能使管理信息和數(shù)據(jù)的信息系統(tǒng)高效、穩(wěn)定的運(yùn)行,其中最重要的措施就是要保證對數(shù)據(jù)庫的高效訪問。然而,隨著數(shù)據(jù)規(guī)模的增大,對數(shù)據(jù)庫的訪問壓力也越來越大,一般的數(shù)據(jù)庫技術(shù)已不能滿足快速、高效地讀取服務(wù)器中的數(shù)據(jù)庫要求。當(dāng)下,Java技術(shù)是用于網(wǎng)絡(luò)中較為流行的一門技術(shù),Java技術(shù)最突出的特點(diǎn)就是跨平臺性,用Java編寫的代碼可移植性較好。在數(shù)據(jù)庫操作中,因?yàn)镴DBC同樣是獨(dú)立于平臺的,所以使用Java API提供的JDBC來連接數(shù)據(jù)庫時,就不用擔(dān)心平臺變更時的代碼移植問題。Java技術(shù)與JDBC的完善結(jié)合,使得Java技術(shù)應(yīng)用越來越廣泛,從而也使得Java訪問數(shù)據(jù)庫的優(yōu)化技術(shù)逐漸備受關(guān)注。如何合理的進(jìn)行數(shù)據(jù)庫設(shè)計(jì)與管理,如何對數(shù)據(jù)庫查詢優(yōu)化,如何在數(shù)據(jù)庫訪問的編程上優(yōu)化等成為本文探討的問題。
在進(jìn)行數(shù)據(jù)庫訪問時,數(shù)據(jù)庫的結(jié)構(gòu)設(shè)計(jì)很重要,結(jié)構(gòu)不合理將直接影響到對數(shù)據(jù)庫的訪問速度、穩(wěn)定等性能。
(一)表結(jié)構(gòu)設(shè)計(jì)
數(shù)據(jù)庫的設(shè)計(jì)實(shí)質(zhì)就是設(shè)計(jì)一個數(shù)據(jù)庫結(jié)構(gòu)的過程,其主要任務(wù)就是設(shè)計(jì)數(shù)據(jù)模式,一個良好的數(shù)據(jù)庫模式應(yīng)具有最小的數(shù)據(jù)冗余,在一定范圍內(nèi)實(shí)現(xiàn)數(shù)據(jù)共享特性,通常數(shù)據(jù)模式設(shè)計(jì)完畢是不輕易改動的,因?yàn)樗仁菓?yīng)用程序存取數(shù)據(jù),處理數(shù)據(jù)的依據(jù),同時也是實(shí)現(xiàn)數(shù)據(jù)物理存儲的依據(jù),因此數(shù)據(jù)模式設(shè)計(jì)的優(yōu)劣嚴(yán)重影響到數(shù)據(jù)庫的訪問性能。在設(shè)計(jì)數(shù)據(jù)模式時盡量滿足3NF,一個關(guān)系模式中每個非主屬性都完全依賴于關(guān)鍵字,關(guān)系模式之間不存在傳遞依賴,關(guān)鍵字段盡量使用單一屬性,不使用復(fù)合屬性,屬性選擇合理,避免數(shù)據(jù)刪除、插入操作等異?,F(xiàn)象發(fā)生。
(二)數(shù)據(jù)庫類型選擇
數(shù)據(jù)庫類型繁多,有簡單易操作的Excel,有面向中小型應(yīng)用的Visual Foxpro、Access、My SQL、 SQL Server、DB2,有面向大型應(yīng)用的Oracle等。從簡單易操作來考慮,首選Excel、Access、SQL Server,從開放性角度考慮,首選Oracle,Oracle完全支持所有的工業(yè)標(biāo)準(zhǔn),采用完全開放策略,完全向下兼容,沒有風(fēng)險,但是Oracle操作復(fù)雜。因此,對于一般的中小型應(yīng)用系統(tǒng),應(yīng)盡量考慮應(yīng)用場合,使用人員水平等,遵循不勿高,不勿優(yōu)原則。
(一)優(yōu)化查詢語句
在進(jìn)行數(shù)據(jù)庫查詢操作時,如果SQL查詢語句設(shè)計(jì)不合理,也會影響到數(shù)據(jù)庫的訪問效率,因此需要對SQL查詢語句進(jìn)行優(yōu)化。通過盡可能的減少SQL查詢語句的運(yùn)行時間,盡可能的少用聯(lián)表查詢,在SQL查詢語句的where子語句中慎用in和not in,避免在where子語句中進(jìn)行函數(shù)操作,優(yōu)化where子語句中的條件順序等方式來加快數(shù)據(jù)庫的查詢速度。
(二)建立索引
SQL查詢語言在索引技術(shù)支持下才能夠提高操作效率,索引會按我們要查詢的列進(jìn)行邏輯排序,盡量不使用復(fù)合索引,為了加快查詢速度盡量使用聚簇索引,該索引不額外增加存儲空間。通過索引的建立,加快數(shù)據(jù)的檢索、顯示、查詢等操作的速度。
通過SQL語句,可以實(shí)現(xiàn)數(shù)據(jù)庫的增、刪、改、查操作。但是,應(yīng)用程序中的SQL語句如何傳到數(shù)據(jù)庫中執(zhí)行,數(shù)據(jù)庫的執(zhí)行結(jié)果如何返回到應(yīng)用程序中,該問題的解決方案就是在應(yīng)用程序和數(shù)據(jù)庫之間必須建立一條通道,這條通道提供SQL語句的發(fā)送和執(zhí)行結(jié)果的返回。建立通道的方式有ODBC開放式數(shù)據(jù)庫連接和JDBC數(shù)據(jù)庫連接應(yīng)用程序接口。JDBC是Java DataBase Connectivity的簡稱,是一種可執(zhí)行SQL語句并可返回結(jié)果的Java 應(yīng)用程序接口,它描述了如何使用SQL去連接數(shù)據(jù)源。JDBC制定了統(tǒng)一的訪問各類關(guān)系數(shù)據(jù)庫的標(biāo)準(zhǔn)接口,雖然在具體的使用過程中,往往由于數(shù)據(jù)庫的不同,需要修改數(shù)據(jù)庫的連接代碼,但是JDBC最大的特點(diǎn)就是獨(dú)立于具體的關(guān)系數(shù)據(jù)庫,即與數(shù)據(jù)庫的無關(guān)性。使用JDBC訪問數(shù)據(jù)庫多有以下兩種結(jié)構(gòu),要通過JDBC來存取某一特定的數(shù)據(jù)庫,必須有相應(yīng)的JDBC驅(qū)動,選擇何種驅(qū)動方式對數(shù)據(jù)庫的訪問性能有很大影響。
(一)JDBC-ODBC橋和ODBC驅(qū)動模式
ODBC是Open DataBase Connectivity的簡稱,是由Microsoft公司提供的應(yīng)用程序接口,它負(fù)責(zé)連接各種不同產(chǎn)商和類型的關(guān)系型數(shù)據(jù)庫系統(tǒng),為各種不同的編程語言提供查詢、插入、修改和刪除數(shù)據(jù)的功能,如同在各種不同的DBMS和各種不同的編程語言之間架設(shè)了一座通用的橋梁。雖然不同的數(shù)據(jù)庫,連接方式是不同的,就像安裝不同品牌的打印機(jī)需要安裝相應(yīng)的驅(qū)動程序才能正常工作一樣。但是ODBC類似于數(shù)據(jù)庫的萬能驅(qū)動,可以和多種數(shù)據(jù)庫連接,如Access,dBase,SQL Server,Oracle等。但是JAVA應(yīng)用程序無法和ODBC直接連接,于是原SUN公司提供JDBC-ODBC橋驅(qū)動類,完成JAVA應(yīng)用程序和ODBC的連接。JDBC-ODBC橋驅(qū)動模式一般用來存取Microsoft Access數(shù)據(jù)庫、Visual FoxPro數(shù)據(jù)庫等,此驅(qū)動程序適合于開發(fā)小規(guī)模的應(yīng)用程序。雖然JDBC-ODBC橋提供了非常方便的免費(fèi)連接驅(qū)動,但在連接時要進(jìn)行一些不必須的轉(zhuǎn)換,而影響了數(shù)據(jù)庫操作效率,在大量的數(shù)據(jù)操作的情況下,JDBCODBC橋驅(qū)動無法滿足查詢速度的需要,另外,由于JDBCODBC橋驅(qū)動不是純JAVA驅(qū)動,影響程序的跨平臺執(zhí)行,因此該驅(qū)動方式一般適用于測試,不作為軟件產(chǎn)品的代碼。
(二)純JAVA的JDBC驅(qū)動程序
為了解決JDBC-ODBC橋驅(qū)動的弊端,在JAVA數(shù)據(jù)庫編程中通常采用JDBC直連的方式訪問數(shù)據(jù)庫,數(shù)據(jù)庫廠商提供純JAVA的JDBC驅(qū)動程序,開發(fā)者在應(yīng)用程序中只需通過調(diào)用JDBC API建立應(yīng)用程序到數(shù)據(jù)庫的連接即可。該模式的優(yōu)點(diǎn)是驅(qū)動由數(shù)據(jù)庫廠商提供,匹配性能更好,無需ODBC轉(zhuǎn)發(fā),執(zhí)行效率高。由于JDBC驅(qū)動是數(shù)據(jù)庫廠商提供的,因此在數(shù)據(jù)庫編程中,用到何種數(shù)據(jù)庫就需要在應(yīng)用程序中添加相應(yīng)的驅(qū)動程序包。以SQL 2008數(shù)據(jù)庫為例,連接SQL 2008數(shù)據(jù)庫需要用到的包有sqljdbc.jar或sqljdbc4. jar。連接SQL 2008數(shù)據(jù)庫時加載驅(qū)動的代碼為:Class. forName("com.microsoft.sqlserver.jdbc.SQLServerDriver");建立連接的URL代碼為:
String url=”jdbc:sqlserver:// localhost:1433;databasename=數(shù)據(jù)源名”;
通常,如果是在實(shí)驗(yàn)性的環(huán)境下,則以JDBC-ODBC橋和ODBC驅(qū)動模式最為常用,在小型應(yīng)用中多以純JAVA的JDBC驅(qū)動程序模式訪問數(shù)據(jù)庫。無論是哪一種驅(qū)動模式,JDBC主要完成以下四方面的工作:①加載JDBC驅(qū)動程序;②建立與數(shù)據(jù)庫的連接;③使用SQL語句進(jìn)行數(shù)據(jù)庫操作并處理結(jié)果;④關(guān)閉相關(guān)連接。
JDBC連接數(shù)據(jù)庫之后就可以對數(shù)據(jù)庫表進(jìn)行操作了,使用編程技術(shù)即可實(shí)現(xiàn)數(shù)據(jù)庫表記錄的增、刪、改等操作,但是不同的程序代碼對數(shù)據(jù)庫表的操作效率不一樣,有必要對數(shù)據(jù)庫訪問編程優(yōu)化。
(一)使用預(yù)處理
Java.sql包中有個重要接口Statement,Statement用于執(zhí)行靜態(tài) SQL 語句并返回所生成結(jié)果的對象。例如ResultSet rst=stmt. Execute(“select * from student where 性別=’女’”); SQL語句的執(zhí)行分兩個過程先編譯再執(zhí)行,通過Statement對象發(fā)送SQL語句時,DBMS負(fù)責(zé)解釋指令,執(zhí)行指令,完成相關(guān)的數(shù)據(jù)庫操作。如果用戶不斷的向數(shù)據(jù)庫提交SQL語句,勢必增加DBMS的負(fù)擔(dān),影響執(zhí)行速度。在多次發(fā)送SQL語句的前提下,可使用PreparedStatement接口對象完成SQL語句的發(fā)送操作,PreparedStatement繼承Statement,它完全繼承Statement的所有操作,但是又不同于Statement,當(dāng)使用PreparedStatement發(fā)送SQL語句時,大多數(shù)情況下這個SQL語句已經(jīng)事先編譯過,因而DBMS無需臨時編譯,只需執(zhí)行即可。這不僅節(jié)省了SQL語句的編譯時間,也減輕了DBMS的負(fù)擔(dān),從而提高了數(shù)據(jù)庫的訪問效率,因此PreparedStatement對象習(xí)慣性被稱為預(yù)處理語句對象。當(dāng)然使用PreparedStatement對象提高數(shù)據(jù)庫訪問效率的前提是SQL語句被多次發(fā)送,如果只發(fā)送一次SQL語句則使用PreparedStatement對象與Statement對象效率一樣。
使用PreparedStatement對象可以執(zhí)行動態(tài)的SQL語句,當(dāng)有些操作只是SQL語句的某些參數(shù)會有些不同,其余的SQL子句皆相同時,則可以使用PreparedStatement對象來提高執(zhí)行效率,而且還可以避免Statement對象發(fā)送SQL語句的SQL注入問題,通過setXXX方法指定相應(yīng)參數(shù),有效地解決了SQL注入問題。
(二)調(diào)用存儲過程
存儲過程在概念上類似于程序中的函數(shù),它以黑盒形式運(yùn)行并返回相應(yīng)信息,存儲過程由數(shù)據(jù)引擎執(zhí)行,無論是將信息輸入到存儲過程還是從存儲過程將信息輸出都必須通過與數(shù)據(jù)庫交互的技術(shù)來完成的。CallableStatement對象為所有的DBMS提供了一種以標(biāo)準(zhǔn)形式調(diào)用存儲過程的方法,CallableStatement對象與PreparedStatement對象一樣都是一個預(yù)處理語句對象,可被多次使用,但是相對于Statement對象和PreparedStatement對象其具有以下優(yōu)點(diǎn):
1. 存儲過程在服務(wù)器端運(yùn)行,執(zhí)行速度快。
2. 存儲過程執(zhí)行一次后,其字節(jié)碼文件就駐留高速緩沖存儲器,在以后的操作中,無需再編譯即可執(zhí)行,提高了系統(tǒng)性能。
3. 自動完成需要預(yù)先執(zhí)行的任務(wù),不必在系統(tǒng)啟動后再進(jìn)行手工操作,大大方便用戶的使用。
(三)使用數(shù)據(jù)集對象轉(zhuǎn)存技術(shù)
當(dāng)對數(shù)據(jù)庫中的數(shù)據(jù)記錄進(jìn)行操作時,一般都是先將數(shù)據(jù)記錄暫存在ResultSet對象中,在需要時再將其傳遞給所需的對象,但是,使用ResultSet對象暫存數(shù)據(jù)記錄的前提是一直需要與數(shù)據(jù)庫保持連接,系統(tǒng)資源將一直被占用而無法釋放。數(shù)據(jù)集對象轉(zhuǎn)存技術(shù)就是將ResultSet對象保存的數(shù)據(jù)記錄轉(zhuǎn)存到CachedRowSetImpl對象中,CachedRowSetImpl對象既可以保存ResultSet對象中的數(shù)據(jù),而且不依賴于Connection對象,這意味著即使關(guān)閉數(shù)據(jù)庫連接也能訪問數(shù)據(jù)庫表中的數(shù)據(jù),這樣ResultSet對象,Statement對象以及Connection對象都可以提前關(guān)閉,釋放了系統(tǒng)資源,提高了系統(tǒng)性能。
另外當(dāng)進(jìn)行分頁顯示操作時,使用數(shù)據(jù)庫提供的定位集的SQL語句,可以有效的提高執(zhí)行效率。此方法是將獲取的查詢請求的行范圍作為參數(shù),通過這些參數(shù)生成SQL查詢語句,然后每次請求獲得一個數(shù)據(jù)庫連接對象并執(zhí)行SQL查詢,把查詢結(jié)果返回給用戶,最后釋放所有的數(shù)據(jù)庫訪問資源,該種方法無論是從內(nèi)存資源占用角度還是數(shù)據(jù)庫資源占用角度看都是最為合理的,也是效率最高的一種形式。
(四)JSP程序開發(fā)模式選擇
JSP程序開發(fā)模式有四種:1. 單純的JSP頁面編程。2. JSP+JavaBean編程。3. JSP+Servlet+JavaBean編程。4. MVC模式。對于單純的JSP頁面編程模式,是將訪問數(shù)據(jù)庫的所有代碼都寫入了JSP頁面,這樣會導(dǎo)致編程難度加大,同時代碼的可維護(hù)性和重用性都得不到滿足。因此,盡可能的避免在JSP頁面中直接寫入大量的邏輯代碼,把訪問數(shù)據(jù)庫的代碼盡可能的放在JavaBean或者Servlet中,這樣,不僅頁面容易維護(hù),代碼也能得到很好的重用。
優(yōu)化Java訪問數(shù)據(jù)庫的效率,應(yīng)該首先從系統(tǒng)的應(yīng)用范圍考慮,選擇合適的數(shù)據(jù)庫,然后再針對不同的應(yīng)用領(lǐng)域選擇合適的驅(qū)動模式,最后針對不同的數(shù)據(jù)庫操作在編程中盡可能的優(yōu)化。當(dāng)然,除了本文中提到的方法之外,還可以使用連接池技術(shù)等達(dá)到優(yōu)化的目的,另外,硬件配置的提高也是優(yōu)化Java訪問數(shù)據(jù)庫效率的重要方面,我們應(yīng)該根據(jù)實(shí)際需要,采用硬、軟件相結(jié)合的方式,以達(dá)到提高Java訪問數(shù)據(jù)庫效率的目的。
作者單位:廣東外語外貿(mào)大學(xué)南國商學(xué)院信息科學(xué)技術(shù)學(xué)院