初識(shí)高速緩存和連接池
設(shè)想這樣一種情形:你突然口渴,需要一杯水來(lái)緩解,從心情上來(lái)講,當(dāng)然是越快越好了。通常,一杯水的產(chǎn)生包括從水源(井水、河水或江水、甚至海水等)抽取,通過(guò)管道傳輸和設(shè)備凈化,才到達(dá)你飲水的容器中。上述過(guò)程是必須的,但并不是每一杯水的產(chǎn)生都必須把上述過(guò)程重復(fù)一次。你可以用一個(gè)大一點(diǎn)的容器(例如缸或罐等)來(lái)盛大量的水,喝水之前分到杯子小部分中即可,你的代價(jià)只是把水從缸轉(zhuǎn)移到杯子;你還可以在大量用水(例如洗澡或洗衣服等)時(shí),只需打開(kāi)水閥,而不必臨時(shí)鋪設(shè)通往水源的管道和購(gòu)買凈化水的設(shè)備。因?yàn)樗侨藗兩畈豢扇鄙俚臇|西,每時(shí)每刻都在被大量地使用,而且物理本質(zhì)也完全相同,所以政府會(huì)鋪設(shè)管道和建設(shè)水處理站,完成那些比較困難的工作,達(dá)到資源共享的目的,而你也可針對(duì)自己的需求,用容器來(lái)盛那些具有特定用途的水。本文將要和你討論的高速緩存和連接池與上述特定容器和傳輸管道有很多相似之處,它們都達(dá)到了同一個(gè)目的:在滿足用戶意愿的前提下,盡可能地共享資源,以提高整個(gè)系統(tǒng)的性能。
高速緩存和連接池是數(shù)據(jù)訪問(wèn)中的重要技術(shù),某些情況下的應(yīng)用對(duì)訪問(wèn)數(shù)據(jù)庫(kù)的性能有巨大的提高,而且都得到了數(shù)據(jù)庫(kù)業(yè)界的普遍支持。前者由DBMS廠商針對(duì)自己的數(shù)據(jù)庫(kù)實(shí)現(xiàn),提供可供用戶配置的方案;后者是JDBC的一個(gè)標(biāo)準(zhǔn)接口,由支持J2EE技術(shù)的應(yīng)用服務(wù)器廠商提供具體的實(shí)現(xiàn),而你的Java程序代碼無(wú)需更改。本文將向你簡(jiǎn)單介紹高速緩存和連接池的概念和機(jī)制,并以PointBase數(shù)據(jù)庫(kù)為例向你展示高速緩存的應(yīng)用,而一個(gè)簡(jiǎn)單的連接池應(yīng)用場(chǎng)景將向你描述應(yīng)用的條件和提高的性能。
Cache(高速緩存)和Connection Pool(連接池)的概念和機(jī)制
它們不是數(shù)據(jù)庫(kù)獨(dú)有的技術(shù),但卻得到數(shù)據(jù)庫(kù)業(yè)界的普遍支持,并在其它數(shù)據(jù)存取和對(duì)象復(fù)用領(lǐng)域有很多類似的應(yīng)用。
Cache(高速緩存)
作為個(gè)人計(jì)算機(jī)的日常使用者,你肯定聽(tīng)說(shuō)過(guò)這些名詞:Cache(高速緩存)、Memory(內(nèi)存)、Hard disk(硬盤)。它們都是數(shù)據(jù)存取單元,但存取速度卻有很大差異,呈依次遞減的順序。對(duì)于CPU來(lái)說(shuō),它可以從距離自己最近的Cache高速地存取數(shù)據(jù),而不是從內(nèi)存和硬盤以低幾個(gè)數(shù)量級(jí)的速度來(lái)存取數(shù)據(jù)。而Cache中所存儲(chǔ)的數(shù)據(jù),往往是CPU要反復(fù)存取的數(shù)據(jù),有特定的機(jī)制(或程序)來(lái)保證Cache內(nèi)數(shù)據(jù)的命中率(Hit Rate)。因此,CPU存取數(shù)據(jù)的速度在應(yīng)用高速緩存后得到了巨大的提高。
對(duì)于數(shù)據(jù)庫(kù)來(lái)說(shuō),廠商的做法往往是在內(nèi)存中開(kāi)辟相應(yīng)的區(qū)域來(lái)存儲(chǔ)可能被多次存取的數(shù)據(jù)和可能被多次執(zhí)行的語(yǔ)句,以使這些數(shù)據(jù)在下次被訪問(wèn)時(shí)不必再次提交對(duì)DBMS的請(qǐng)求和那些語(yǔ)句在下次執(zhí)行時(shí)不必再次編譯。
因?yàn)閷?shù)據(jù)寫入高速緩存的任務(wù)由Cache Manager負(fù)責(zé),所以對(duì)用戶來(lái)說(shuō)高速緩存的內(nèi)容肯定是只讀的。需要你做的工作很少,程序中的SQL語(yǔ)句和直接訪問(wèn)DBMS時(shí)沒(méi)有分別,返回的結(jié)果也看不出有什么差別。而數(shù)據(jù)庫(kù)廠商往往會(huì)在DB Server的配置文件中提供與Cache相關(guān)的參數(shù),通過(guò)修改它們,可針對(duì)我們的應(yīng)用優(yōu)化Cache的管理。下圖是在Win2K中配置MS Access數(shù)據(jù)源的界面,在"驅(qū)動(dòng)程序"部分你可設(shè)置的頁(yè)超時(shí)和緩沖區(qū)大小就是和Cache有關(guān)的參數(shù)。在后面的討論中,我將展示一個(gè)更復(fù)雜的數(shù)據(jù)庫(kù),向你解釋Cache對(duì)訪問(wèn)數(shù)據(jù)庫(kù)性能的影響和如何尋找最優(yōu)的配置方案。
Connection Pool(連接池)
池是一個(gè)很普遍的概念,和緩沖存儲(chǔ)有機(jī)制相近的地方,都是縮減了訪問(wèn)的環(huán)節(jié),但它更注重于資源的共享。下圖展示了建立"調(diào)制解調(diào)器池"以共享調(diào)制解調(diào)器資源的VPN撥號(hào)方案:
對(duì)于訪問(wèn)數(shù)據(jù)庫(kù)來(lái)說(shuō),建立連接的代價(jià)比較昂貴,因此,我們有必要建立"連接池"以提高訪問(wèn)的性能。我們可以把連接當(dāng)作對(duì)象或者設(shè)備,池中又有許多已經(jīng)建立的連接,訪問(wèn)本來(lái)需要與數(shù)據(jù)庫(kù)的連接的地方,都改為和池相連,池臨時(shí)分配連接供訪問(wèn)使用,結(jié)果返回后,訪問(wèn)將連接交還。
JDBC 1.0標(biāo)準(zhǔn)及其擴(kuò)展中沒(méi)有定義連接池,而在JDBC 2.0標(biāo)準(zhǔn)的擴(kuò)展中定義了與連接池相關(guān)的接口。與接口對(duì)應(yīng)的類由應(yīng)用服務(wù)器廠商實(shí)現(xiàn),你可在對(duì)服務(wù)器的管理過(guò)程中調(diào)節(jié)某個(gè)數(shù)據(jù)庫(kù)連接池的參數(shù)。下圖簡(jiǎn)略地描述了連接池的運(yùn)行機(jī)制:
高速緩存的參數(shù)設(shè)定
在PointBase數(shù)據(jù)庫(kù)DB Server的配置參數(shù)列表中,我們可以找到這幾個(gè)參數(shù):cache.checkpointinterval、cache.size、SQLCaching.size等。下表是對(duì)各個(gè)參數(shù)的描述:
參數(shù)名 參數(shù)描述
cache.checkpointinterval 檢查點(diǎn)的時(shí)間間隔
cache.size 高速緩存的最大頁(yè)數(shù)(素?cái)?shù)時(shí),性能最好)
SQLCaching.size 高速緩存中SQL語(yǔ)句的個(gè)數(shù)
對(duì)于cache.checkpointinterval來(lái)說(shuō),和前面Access界面中的頁(yè)超時(shí)是一個(gè)概念,它指定了頁(yè)面內(nèi)容更新的時(shí)間間隔,這取決于你的應(yīng)用對(duì)時(shí)效性的要求程度。
對(duì)于cache.size來(lái)說(shuō),指定了頁(yè)面的個(gè)數(shù),一般應(yīng)設(shè)定為符合你查詢結(jié)果的需求。至于為何是素?cái)?shù),我也納悶,不過(guò)還是遵照廠商的指示吧。
對(duì)于SQLCaching.size來(lái)說(shuō),指定了存儲(chǔ)的經(jīng)過(guò)編譯的SQL語(yǔ)句的個(gè)數(shù),你可以把它設(shè)定為0,從而取消這個(gè)選項(xiàng)。
使用Cache后,性能到底有多大提高?我打開(kāi)PointBase的Console通過(guò)JDBC驅(qū)動(dòng)訪問(wèn)Server,將SQL菜單下的Timing Mode選上,以顯示各個(gè)步驟的耗費(fèi)時(shí)間。執(zhí)行語(yǔ)句是:
SELECT * FROM PRODUCT_TBL
?
?
第一次訪問(wèn),總計(jì)耗時(shí)1082毫秒,而編譯耗時(shí)771毫秒。
緊接著的第二次訪問(wèn),總計(jì)耗時(shí)僅為160毫秒,而編譯耗時(shí)為0。
再接著的第三次訪問(wèn),總計(jì)耗時(shí)僅為91毫秒,編譯耗時(shí)也為0。
關(guān)閉Console,等待超過(guò)30秒之后,重新開(kāi)啟Console,執(zhí)行相同的語(yǔ)句,總計(jì)耗時(shí)210毫秒,編譯耗時(shí)為20毫秒。
自等待超過(guò)30秒之后,執(zhí)行語(yǔ)句,總計(jì)耗時(shí)101毫秒,編譯耗時(shí)為0。
由此可以看出,高速緩存的應(yīng)用大大提高了訪問(wèn)數(shù)據(jù)庫(kù)的性能,而其參數(shù)的設(shè)定則要依據(jù)前面對(duì)它們的描述來(lái)進(jìn)行,需要你仔細(xì)閱讀數(shù)據(jù)庫(kù)的配置文檔。
連接池的設(shè)置和應(yīng)用
我選擇IBM公司的應(yīng)用服務(wù)器平臺(tái)WebSphere來(lái)給大家演示連接池的設(shè)置,使你面對(duì)友好的Web界面,可以體驗(yàn)到非常簡(jiǎn)易的操作場(chǎng)景。
首先,我們進(jìn)入WebSphere的管理控制臺(tái),這是一個(gè)非常漂亮的Web界面:
緊接著,我選定一個(gè)數(shù)據(jù)源:Session Persistence datasource,就可看到這個(gè)數(shù)據(jù)源的屬性配置了。在這兒,僅僅列舉和連接池有關(guān)的屬性:
Minimum Pool Size 池中保持的連接的最小數(shù)目;有新的請(qǐng)求,且沒(méi)有激活連接可供使用時(shí),池中連接數(shù)將增大,到最大連接數(shù)為止
Maximum Pool Size 池中保持的連接的最大數(shù)目;當(dāng)這個(gè)數(shù)目達(dá)到,且沒(méi)有激活連接可供使用時(shí),新的請(qǐng)求將等待
Connection Timeout 當(dāng)連接數(shù)達(dá)到最大值,且激活連接都在被使用時(shí),新的請(qǐng)求等待的時(shí)間
Idle Timeout 連接可在池中閑置的時(shí)間;超過(guò)將釋放資源,到最小連接數(shù)為止
Orphan Timeout 連接在被應(yīng)用控制時(shí),可閑置的時(shí)間;超過(guò)將返回池中
你可以根據(jù)需要來(lái)修改這些數(shù)值,以滿足你的應(yīng)用需要。接下來(lái),我們討論一下連接池的應(yīng)用。
EJB訪問(wèn)數(shù)據(jù)庫(kù)(場(chǎng)景1,使用JDBC 1.0) import java.sql.*;
import javax.sql.*;
...
public class AccountBean implements EntityBean {
...
public Collection ejbFindByLastName(String lName) {
try {
String dbdriver = new initialContext().lookup("java:comp/env/DBDRIVER").toString();
Class.forName(dbdriver).newInstance();
Connection conn = null;
conn = DriverManager.getConnection("java:comp/env/DBURL", "userID", "password");
...
conn.close();
}
...
}
?
?
如果EntityBean是一個(gè)共享組件,那么每次客戶請(qǐng)求時(shí),都要建立和釋放與數(shù)據(jù)庫(kù)的連接,這成為影響性能的主要問(wèn)題。
EJB訪問(wèn)數(shù)據(jù)庫(kù)(場(chǎng)景2,使用JDBC 2.0) import java.sql.*;
import javax.sql.*;
// import here vendor specific JDBC drivers
public ProductPK ejbCreate() {
try {
// initialize JNDI lookup parameters
Context ctx = new InitialContext(parms);
...
ConnectionPoolDataSource cpds = (ConnectionPoolDataSource)ctx.lookup(cpsource);
...
// Following parms could all come from a JNDI look-up
cpds.setDatabaseName("PTDB");
cpds.setUserIF("XYZ");
...
PooledConnection pc = cpds.getPooledConnection();
Connection conn = pc.getConnection();
...
// do business logic
conn.close();
}
...
}
EJB組件利用JNDI的lookup()方法定位數(shù)據(jù)庫(kù)的連接池資源,利用getConnection()方法得到已經(jīng)打開(kāi)的數(shù)據(jù)庫(kù)連接,而用close()來(lái)釋放連接,放回池中。因此,與場(chǎng)景1相比,少了與數(shù)據(jù)庫(kù)建立物理連接的損耗。對(duì)于原本要頻繁打開(kāi)和關(guān)閉物理連接的應(yīng)用來(lái)說(shuō),通過(guò)這種建立邏輯連接并復(fù)用的方法,性能肯定能夠得到大幅度提高。
性能問(wèn)題的深遠(yuǎn)思索
性能問(wèn)題并不局限于數(shù)據(jù)庫(kù)的應(yīng)用上,而是存在于每個(gè)軟件系統(tǒng)中。我們希望軟件系統(tǒng)付出的最小,而獲得的最大,因而無(wú)時(shí)無(wú)刻不在優(yōu)化它們。通過(guò)《Java程序訪問(wèn)數(shù)據(jù)庫(kù)的速度瓶頸問(wèn)題的分析和解決》和本文,我對(duì)Java程序訪問(wèn)數(shù)據(jù)庫(kù)的性能問(wèn)題做了分析,并提供了優(yōu)化Java程序的解決方案,希望對(duì)你有所幫助。
也許你會(huì)關(guān)心碰到類似的性能問(wèn)題時(shí)應(yīng)如何分析和解決,我就針對(duì)此次探討"訪問(wèn)數(shù)據(jù)庫(kù)的速度瓶頸"問(wèn)題的過(guò)程中碰到的難題、網(wǎng)友的意見(jiàn)和自己的體會(huì),作一個(gè)關(guān)于"方法論"的經(jīng)驗(yàn)總結(jié),希望能夠拋磚引玉,更好地解決類似的問(wèn)題。
解決性能問(wèn)題的幾條經(jīng)驗(yàn)
不要讓硬件的低配置成為軟件正常運(yùn)行的障礙,后者有升級(jí)前者的需求,請(qǐng)立即滿足;經(jīng)常碰到這樣的問(wèn)題"P166+64M的機(jī)子跑Win2K+MySql+JBoss,能跑么?"我在回答"可以"的同時(shí)只有對(duì)著屏幕發(fā)呆了。
盡量使用商業(yè)軟件,并享受良好的售后技術(shù)支持;如果你沒(méi)有黑客精神,請(qǐng)不要使用自由軟件。
分析好自己的問(wèn)題,也許它的本質(zhì)和他人的不同;沒(méi)有一把鑰匙可打開(kāi)的任一把鎖。
確定瓶頸環(huán)節(jié)的位置;解決了瓶頸問(wèn)題,往往整個(gè)的性能問(wèn)題就解決了,千萬(wàn)不要抓著邊緣的問(wèn)題不放。
將瓶頸環(huán)節(jié)細(xì)分為多個(gè)順序的流程,用逐個(gè)替代的方法來(lái)試探瓶頸的核心位置;細(xì)分問(wèn)題使你都問(wèn)題有更進(jìn)一步的了解。
做自己能做的和該做的事情,始終面向自己的現(xiàn)實(shí)問(wèn)題;不要嘗試那些應(yīng)該由廠商解決的問(wèn)題(例如,自己寫個(gè)JDBC驅(qū)動(dòng))。
他人的方案只供自己參考,解決要靠自己思考;你我應(yīng)用的情形不同,應(yīng)用解決方案要在理解他人的方案之后。
觀察新技術(shù),應(yīng)用新技術(shù);它往往包含了前人對(duì)問(wèn)題解決的思路,只是對(duì)你來(lái)說(shuō)不可見(jiàn)。
問(wèn)題得到解決后,立即罷手,并匯報(bào)結(jié)果;在現(xiàn)實(shí)問(wèn)題得到解決后,沒(méi)有必要花費(fèi)精力在非核心的問(wèn)題上,也許它們永遠(yuǎn)不會(huì)被碰到,不要假想問(wèn)題讓自己解決。
上述經(jīng)驗(yàn)為個(gè)人即興的總結(jié),并未有嚴(yán)謹(jǐn)?shù)倪壿嬐茖?dǎo),僅代表我解決技術(shù)問(wèn)題的思路,供你碰到類似問(wèn)題時(shí)參考。
可以提前告訴大家的是,下一篇文章我將把主題轉(zhuǎn)移到JDO的介紹和討論上。這個(gè)陌生的API已經(jīng)進(jìn)入Final Draft了,可它到底能夠給數(shù)據(jù)存取帶來(lái)什么好處,和JDBC有什么關(guān)聯(lián)的地方,《JDO(Java Data Object)的發(fā)展和介紹》將向你娓娓道來(lái)。
初識(shí)高速緩存和連接池設(shè)想這樣一種情形:你突然口渴,需要一杯水來(lái)緩解,從心情上來(lái)講,當(dāng)然是越快越好了。通常,一杯水的產(chǎn)生包括從水源(井水、河水或江水、甚至海水等)抽取,通過(guò)管道傳輸和設(shè)備凈化,才到達(dá)你飲水的容器中。上述過(guò)程是必須的,但并不是每一杯水的產(chǎn)生都必須把上述過(guò)程重復(fù)一次。你可以用一個(gè)大一點(diǎn)的容器(例如缸或罐等)來(lái)盛大量的水,喝水之前分到杯子小部分中即可,你的代價(jià)只是把水從缸轉(zhuǎn)移到杯子;你還可以在大量用水(例如洗澡或洗衣服等)時(shí),只需打開(kāi)水閥,而不必臨時(shí)鋪設(shè)通往水源的管道和購(gòu)買凈化水的設(shè)備。因?yàn)樗侨藗兩畈豢扇鄙俚臇|西,每時(shí)每刻都在被大量地使用,而且物理本質(zhì)也完全相同,所以政府會(huì)鋪設(shè)管道和建設(shè)水處理站,完成那些比較困難的工作,達(dá)到資源共享的目的,而你也可針對(duì)自己的需求,用容器來(lái)盛那些具有特定用途的水。本文將要和你討論的高速緩存和連接池與上述特定容器和傳輸管道有很多相似之處,它們都達(dá)到了同一個(gè)目的:在滿足用戶意愿的前提下,盡可能地共享資源,以提高整個(gè)系統(tǒng)的性能。
高速緩存和連接池是數(shù)據(jù)訪問(wèn)中的重要技術(shù),某些情況下的應(yīng)用對(duì)訪問(wèn)數(shù)據(jù)庫(kù)的性能有巨大的提高,而且都得到了數(shù)據(jù)庫(kù)業(yè)界的普遍支持。前者由DBMS廠商針對(duì)自己的數(shù)據(jù)庫(kù)實(shí)現(xiàn),提供可供用戶配置的方案;后者是JDBC的一個(gè)標(biāo)準(zhǔn)接口,由支持J2EE技術(shù)的應(yīng)用服務(wù)器廠商提供具體的實(shí)現(xiàn),而你的Java程序代碼無(wú)需更改。本文將向你簡(jiǎn)單介紹高速緩存和連接池的概念和機(jī)制,并以PointBase數(shù)據(jù)庫(kù)為例向你展示高速緩存的應(yīng)用,而一個(gè)簡(jiǎn)單的連接池應(yīng)用場(chǎng)景將向你描述應(yīng)用的條件和提高的性能。
Cache(高速緩存)和Connection Pool(連接池)的概念和機(jī)制
它們不是數(shù)據(jù)庫(kù)獨(dú)有的技術(shù),但卻得到數(shù)據(jù)庫(kù)業(yè)界的普遍支持,并在其它數(shù)據(jù)存取和對(duì)象復(fù)用領(lǐng)域有很多類似的應(yīng)用。
Cache(高速緩存)
作為個(gè)人計(jì)算機(jī)的日常使用者,你肯定聽(tīng)說(shuō)過(guò)這些名詞:Cache(高速緩存)、Memory(內(nèi)存)、Hard disk(硬盤)。它們都是數(shù)據(jù)存取單元,但存取速度卻有很大差異,呈依次遞減的順序。對(duì)于CPU來(lái)說(shuō),它可以從距離自己最近的Cache高速地存取數(shù)據(jù),而不是從內(nèi)存和硬盤以低幾個(gè)數(shù)量級(jí)的速度來(lái)存取數(shù)據(jù)。而Cache中所存儲(chǔ)的數(shù)據(jù),往往是CPU要反復(fù)存取的數(shù)據(jù),有特定的機(jī)制(或程序)來(lái)保證Cache內(nèi)數(shù)據(jù)的命中率(Hit Rate)。因此,CPU存取數(shù)據(jù)的速度在應(yīng)用高速緩存后得到了巨大的提高。
對(duì)于數(shù)據(jù)庫(kù)來(lái)說(shuō),廠商的做法往往是在內(nèi)存中開(kāi)辟相應(yīng)的區(qū)域來(lái)存儲(chǔ)可能被多次存取的數(shù)據(jù)和可能被多次執(zhí)行的語(yǔ)句,以使這些數(shù)據(jù)在下次被訪問(wèn)時(shí)不必再次提交對(duì)DBMS的請(qǐng)求和那些語(yǔ)句在下次執(zhí)行時(shí)不必再次編譯。
因?yàn)閷?shù)據(jù)寫入高速緩存的任務(wù)由Cache Manager負(fù)責(zé),所以對(duì)用戶來(lái)說(shuō)高速緩存的內(nèi)容肯定是只讀的。需要你做的工作很少,程序中的SQL語(yǔ)句和直接訪問(wèn)DBMS時(shí)沒(méi)有分別,返回的結(jié)果也看不出有什么差別。而數(shù)據(jù)庫(kù)廠商往往會(huì)在DB Server的配置文件中提供與Cache相關(guān)的參數(shù),通過(guò)修改它們,可針對(duì)我們的應(yīng)用優(yōu)化Cache的管理。下圖是在Win2K中配置MS Access數(shù)據(jù)源的界面,在"驅(qū)動(dòng)程序"部分你可設(shè)置的頁(yè)超時(shí)和緩沖區(qū)大小就是和Cache有關(guān)的參數(shù)。在后面的討論中,我將展示一個(gè)更復(fù)雜的數(shù)據(jù)庫(kù),向你解釋Cache對(duì)訪問(wèn)數(shù)據(jù)庫(kù)性能的影響和如何尋找最優(yōu)的配置方案。
Connection Pool(連接池)
池是一個(gè)很普遍的概念,和緩沖存儲(chǔ)有機(jī)制相近的地方,都是縮減了訪問(wèn)的環(huán)節(jié),但它更注重于資源的共享。下圖展示了建立"調(diào)制解調(diào)器池"以共享調(diào)制解調(diào)器資源的VPN撥號(hào)方案:
對(duì)于訪問(wèn)數(shù)據(jù)庫(kù)來(lái)說(shuō),建立連接的代價(jià)比較昂貴,因此,我們有必要建立"連接池"以提高訪問(wèn)的性能。我們可以把連接當(dāng)作對(duì)象或者設(shè)備,池中又有許多已經(jīng)建立的連接,訪問(wèn)本來(lái)需要與數(shù)據(jù)庫(kù)的連接的地方,都改為和池相連,池臨時(shí)分配連接供訪問(wèn)使用,結(jié)果返回后,訪問(wèn)將連接交還。
JDBC 1.0標(biāo)準(zhǔn)及其擴(kuò)展中沒(méi)有定義連接池,而在JDBC 2.0標(biāo)準(zhǔn)的擴(kuò)展中定義了與連接池相關(guān)的接口。與接口對(duì)應(yīng)的類由應(yīng)用服務(wù)器廠商實(shí)現(xiàn),你可在對(duì)服務(wù)器的管理過(guò)程中調(diào)節(jié)某個(gè)數(shù)據(jù)庫(kù)連接池的參數(shù)。下圖簡(jiǎn)略地描述了連接池的運(yùn)行機(jī)制:
高速緩存的參數(shù)設(shè)定
在PointBase數(shù)據(jù)庫(kù)DB Server的配置參數(shù)列表中,我們可以找到這幾個(gè)參數(shù):cache.checkpointinterval、cache.size、SQLCaching.size等。下表是對(duì)各個(gè)參數(shù)的描述:
參數(shù)名 參數(shù)描述
cache.checkpointinterval 檢查點(diǎn)的時(shí)間間隔
cache.size 高速緩存的最大頁(yè)數(shù)(素?cái)?shù)時(shí),性能最好)
SQLCaching.size 高速緩存中SQL語(yǔ)句的個(gè)數(shù)
對(duì)于cache.checkpointinterval來(lái)說(shuō),和前面Access界面中的頁(yè)超時(shí)是一個(gè)概念,它指定了頁(yè)面內(nèi)容更新的時(shí)間間隔,這取決于你的應(yīng)用對(duì)時(shí)效性的要求程度。
對(duì)于cache.size來(lái)說(shuō),指定了頁(yè)面的個(gè)數(shù),一般應(yīng)設(shè)定為符合你查詢結(jié)果的需求。至于為何是素?cái)?shù),我也納悶,不過(guò)還是遵照廠商的指示吧。
對(duì)于SQLCaching.size來(lái)說(shuō),指定了存儲(chǔ)的經(jīng)過(guò)編譯的SQL語(yǔ)句的個(gè)數(shù),你可以把它設(shè)定為0,從而取消這個(gè)選項(xiàng)。
使用Cache后,性能到底有多大提高?我打開(kāi)PointBase的Console通過(guò)JDBC驅(qū)動(dòng)訪問(wèn)Server,將SQL菜單下的Timing Mode選上,以顯示各個(gè)步驟的耗費(fèi)時(shí)間。執(zhí)行語(yǔ)句是:
SELECT * FROM PRODUCT_TBL
?
?
第一次訪問(wèn),總計(jì)耗時(shí)1082毫秒,而編譯耗時(shí)771毫秒。
緊接著的第二次訪問(wèn),總計(jì)耗時(shí)僅為160毫秒,而編譯耗時(shí)為0。
再接著的第三次訪問(wèn),總計(jì)耗時(shí)僅為91毫秒,編譯耗時(shí)也為0。
關(guān)閉Console,等待超過(guò)30秒之后,重新開(kāi)啟Console,執(zhí)行相同的語(yǔ)句,總計(jì)耗時(shí)210毫秒,編譯耗時(shí)為20毫秒。
自等待超過(guò)30秒之后,執(zhí)行語(yǔ)句,總計(jì)耗時(shí)101毫秒,編譯耗時(shí)為0。
由此可以看出,高速緩存的應(yīng)用大大提高了訪問(wèn)數(shù)據(jù)庫(kù)的性能,而其參數(shù)的設(shè)定則要依據(jù)前面對(duì)它們的描述來(lái)進(jìn)行,需要你仔細(xì)閱讀數(shù)據(jù)庫(kù)的配置文檔。
連接池的設(shè)置和應(yīng)用
我選擇IBM公司的應(yīng)用服務(wù)器平臺(tái)WebSphere來(lái)給大家演示連接池的設(shè)置,使你面對(duì)友好的Web界面,可以體驗(yàn)到非常簡(jiǎn)易的操作場(chǎng)景。
首先,我們進(jìn)入WebSphere的管理控制臺(tái),這是一個(gè)非常漂亮的Web界面:
緊接著,我選定一個(gè)數(shù)據(jù)源:Session Persistence datasource,就可看到這個(gè)數(shù)據(jù)源的屬性配置了。在這兒,僅僅列舉和連接池有關(guān)的屬性:
Minimum Pool Size 池中保持的連接的最小數(shù)目;有新的請(qǐng)求,且沒(méi)有激活連接可供使用時(shí),池中連接數(shù)將增大,到最大連接數(shù)為止
Maximum Pool Size 池中保持的連接的最大數(shù)目;當(dāng)這個(gè)數(shù)目達(dá)到,且沒(méi)有激活連接可供使用時(shí),新的請(qǐng)求將等待
Connection Timeout 當(dāng)連接數(shù)達(dá)到最大值,且激活連接都在被使用時(shí),新的請(qǐng)求等待的時(shí)間
Idle Timeout 連接可在池中閑置的時(shí)間;超過(guò)將釋放資源,到最小連接數(shù)為止
Orphan Timeout 連接在被應(yīng)用控制時(shí),可閑置的時(shí)間;超過(guò)將返回池中
你可以根據(jù)需要來(lái)修改這些數(shù)值,以滿足你的應(yīng)用需要。接下來(lái),我們討論一下連接池的應(yīng)用。
EJB訪問(wèn)數(shù)據(jù)庫(kù)(場(chǎng)景1,使用JDBC 1.0) import java.sql.*;
import javax.sql.*;
...
public class AccountBean implements EntityBean {
...
public Collection ejbFindByLastName(String lName) {
try {
String dbdriver = new initialContext().lookup("java:comp/env/DBDRIVER").toString();
Class.forName(dbdriver).newInstance();
Connection conn = null;
conn = DriverManager.getConnection("java:comp/env/DBURL", "userID", "password");
...
conn.close();
}
...
}
?
?
如果EntityBean是一個(gè)共享組件,那么每次客戶請(qǐng)求時(shí),都要建立和釋放與數(shù)據(jù)庫(kù)的連接,這成為影響性能的主要問(wèn)題。
EJB訪問(wèn)數(shù)據(jù)庫(kù)(場(chǎng)景2,使用JDBC 2.0) import java.sql.*;
import javax.sql.*;
// import here vendor specific JDBC drivers
public ProductPK ejbCreate() {
try {
// initialize JNDI lookup parameters
Context ctx = new InitialContext(parms);
...
ConnectionPoolDataSource cpds = (ConnectionPoolDataSource)ctx.lookup(cpsource);
...
// Following parms could all come from a JNDI look-up
cpds.setDatabaseName("PTDB");
cpds.setUserIF("XYZ");
...
PooledConnection pc = cpds.getPooledConnection();
Connection conn = pc.getConnection();
...
// do business logic
conn.close();
}
...
}
EJB組件利用JNDI的lookup()方法定位數(shù)據(jù)庫(kù)的連接池資源,利用getConnection()方法得到已經(jīng)打開(kāi)的數(shù)據(jù)庫(kù)連接,而用close()來(lái)釋放連接,放回池中。因此,與場(chǎng)景1相比,少了與數(shù)據(jù)庫(kù)建立物理連接的損耗。對(duì)于原本要頻繁打開(kāi)和關(guān)閉物理連接的應(yīng)用來(lái)說(shuō),通過(guò)這種建立邏輯連接并復(fù)用的方法,性能肯定能夠得到大幅度提高。
性能問(wèn)題的深遠(yuǎn)思索
性能問(wèn)題并不局限于數(shù)據(jù)庫(kù)的應(yīng)用上,而是存在于每個(gè)軟件系統(tǒng)中。我們希望軟件系統(tǒng)付出的最小,而獲得的最大,因而無(wú)時(shí)無(wú)刻不在優(yōu)化它們。通過(guò)《Java程序訪問(wèn)數(shù)據(jù)庫(kù)的速度瓶頸問(wèn)題的分析和解決》和本文,我對(duì)Java程序訪問(wèn)數(shù)據(jù)庫(kù)的性能問(wèn)題做了分析,并提供了優(yōu)化Java程序的解決方案,希望對(duì)你有所幫助。
也許你會(huì)關(guān)心碰到類似的性能問(wèn)題時(shí)應(yīng)如何分析和解決,我就針對(duì)此次探討"訪問(wèn)數(shù)據(jù)庫(kù)的速度瓶頸"問(wèn)題的過(guò)程中碰到的難題、網(wǎng)友的意見(jiàn)和自己的體會(huì),作一個(gè)關(guān)于"方法論"的經(jīng)驗(yàn)總結(jié),希望能夠拋磚引玉,更好地解決類似的問(wèn)題。
解決性能問(wèn)題的幾條經(jīng)驗(yàn)
不要讓硬件的低配置成為軟件正常運(yùn)行的障礙,后者有升級(jí)前者的需求,請(qǐng)立即滿足;經(jīng)常碰到這樣的問(wèn)題"P166+64M的機(jī)子跑Win2K+MySql+JBoss,能跑么?"我在回答"可以"的同時(shí)只有對(duì)著屏幕發(fā)呆了。
盡量使用商業(yè)軟件,并享受良好的售后技術(shù)支持;如果你沒(méi)有黑客精神,請(qǐng)不要使用自由軟件。
分析好自己的問(wèn)題,也許它的本質(zhì)和他人的不同;沒(méi)有一把鑰匙可打開(kāi)的任一把鎖。
確定瓶頸環(huán)節(jié)的位置;解決了瓶頸問(wèn)題,往往整個(gè)的性能問(wèn)題就解決了,千萬(wàn)不要抓著邊緣的問(wèn)題不放。
將瓶頸環(huán)節(jié)細(xì)分為多個(gè)順序的流程,用逐個(gè)替代的方法來(lái)試探瓶頸的核心位置;細(xì)分問(wèn)題使你都問(wèn)題有更進(jìn)一步的了解。
做自己能做的和該做的事情,始終面向自己的現(xiàn)實(shí)問(wèn)題;不要嘗試那些應(yīng)該由廠商解決的問(wèn)題(例如,自己寫個(gè)JDBC驅(qū)動(dòng))。
他人的方案只供自己參考,解決要靠自己思考;你我應(yīng)用的情形不同,應(yīng)用解決方案要在理解他人的方案之后。
觀察新技術(shù),應(yīng)用新技術(shù);它往往包含了前人對(duì)問(wèn)題解決的思路,只是對(duì)你來(lái)說(shuō)不可見(jiàn)。
問(wèn)題得到解決后,立即罷手,并匯報(bào)結(jié)果;在現(xiàn)實(shí)問(wèn)題得到解決后,沒(méi)有必要花費(fèi)精力在非核心的問(wèn)題上,也許它們永遠(yuǎn)不會(huì)被碰到,不要假想問(wèn)題讓自己解決。
上述經(jīng)驗(yàn)為個(gè)人即興的總結(jié),并未有嚴(yán)謹(jǐn)?shù)倪壿嬐茖?dǎo),僅代表我解決技術(shù)問(wèn)題的思路,供你碰到類似問(wèn)題時(shí)參考。
可以提前告訴大家的是,下一篇文章我將把主題轉(zhuǎn)移到JDO的介紹和討論上。這個(gè)陌生的API已經(jīng)進(jìn)入Final Draft了,可它到底能夠給數(shù)據(jù)存取帶來(lái)什么好處,和JDBC有什么關(guān)聯(lián)的地方,《JDO(Java Data Object)的發(fā)展和介紹》將向你娓娓道來(lái)。
]]>