談?wù)剝?yōu)化JDBC數(shù)據(jù)庫編程
JDBC數(shù)據(jù)庫編程1.盡量減少對(duì)數(shù)據(jù)庫元數(shù)據(jù)方法的使用
同樣是產(chǎn)生一個(gè)ResultSet對(duì)象,DatabaseMetaData 對(duì)象的方法比其它JDBC方法相對(duì)要慢,因此平繁使用該方法會(huì)降低系統(tǒng)的性能。 在程序中應(yīng)當(dāng)對(duì)產(chǎn)生的結(jié)果集信息進(jìn)行高速緩存,比如將getTypeInfo()返回的結(jié)果集存入Vector或Hashtable中,這樣可大大提高程序的效率。
JDBC數(shù)據(jù)庫編程2.應(yīng)避免的方法調(diào)用模式
在方法調(diào)用時(shí)應(yīng)當(dāng)盡量避免傳入null做為參數(shù),雖然有時(shí)能執(zhí)行成功,但這對(duì)DB Server負(fù)擔(dān)很重。其實(shí)在很多情況下所需的參數(shù)是已知的。比如:
- //這里略去了捕獲違例代碼(下同)。
- DatabaseMetaData md=...;
- ResultSet rs=md.getTables(null,null,"authors",null);//取得MS SQL SERVER pubs數(shù)據(jù)庫中authors表的信息.
應(yīng)當(dāng)寫成:
- ResultSet rs=md.getTables("northwind","dbo","authors",new String[]{"TABLE"});
這樣使程序更有效可靠。
JDBC數(shù)據(jù)庫編程3.使用啞查詢語句來取得表的相關(guān)特征信息
一個(gè)啞查詢語句(Dummy Query,譯為啞查詢不知是否恰當(dāng),愿與大家探討)不會(huì)產(chǎn)生有記錄的結(jié)果集,比如:select * from tableName where 1=0,因?yàn)闂l件永不成立,DB Server 不會(huì)執(zhí)行這條語句。因此,在不需產(chǎn)生記錄行的情況下,啞查詢能極大地提高程序的執(zhí)行效率。比如我們要了解一個(gè)表的有關(guān)列信息時(shí),上面的語句比select * from tableName這個(gè)語句要高效得多,后者數(shù)據(jù)庫服務(wù)器要檢索所有的行并返回一個(gè)記錄集,而前者不需要。針對(duì)這一問題,JDBC可以有以下兩種方法:
- case1:使用getColumns()方法
- //getColumns()是DatabaseMetaData的一個(gè)方法,其有關(guān)信息請(qǐng)查閱JDK1.3文檔
- ResultSetrs=md.getColumns("pubs","dbo","authors",...);//返回一個(gè)有記錄的結(jié)果集
- while(rs.next())//通過滾動(dòng)結(jié)果集取得列名
- System.out.println(rs.getString(4));
- case2:使用getMetaData()方法
- Statementstmt=conn.createStatement();
- //數(shù)據(jù)庫服務(wù)器永遠(yuǎn)不會(huì)執(zhí)行這條查詢語句
- ResultSetrs=stmt.executeQuery("select*fromauthorswhere1=0");
- ResultSetMetaDatarsrsmd=rs.getMetaData();
- intcolCount=rsmd.getColumnCount();//取得列數(shù)
- for(intcol=1;col<=colCount;col++)
- System.out.println(rsmd.getColumnName(col));
- //!這里列的順序是select后列出現(xiàn)的順序,并不一定與表中列順序?qū)?yīng)
通過以上的分析,第二種方法應(yīng)是我們的選擇。
JDBC數(shù)據(jù)庫編程4.關(guān)于存儲(chǔ)過程的調(diào)用
由于所有的JDBC驅(qū)動(dòng)總是將SQL語句作為字符串發(fā)送到數(shù)據(jù)庫服務(wù)器,數(shù)據(jù)庫服務(wù)器經(jīng)過語法分析、參數(shù)類型驗(yàn)證,然后將參數(shù)轉(zhuǎn)換成正確的數(shù)據(jù)類型再去執(zhí)行。比如有這么一個(gè)存儲(chǔ)過程:
- CallableStatementcstmt=conn.prepareCall("{callgetCustomerName(123)}");
- //獲得指定id的客戶的名字,輸入?yún)?shù),id是個(gè)正整數(shù)
- ResultSetrs=cstmt.executeQuery();
在這里我們認(rèn)為123是一個(gè)正整數(shù),但實(shí)際"call getCustomerName(123)"作為字符串整個(gè)被發(fā)送到數(shù)據(jù)庫服務(wù)器端,數(shù)據(jù)庫服務(wù)器經(jīng)過分析,離析出"123"將其轉(zhuǎn)換為整數(shù)型值再做為參數(shù)送給存儲(chǔ)過程執(zhí)行。很明顯,這樣效率極低,因?yàn)槲覀儼岩阎臇|西仍要服務(wù)器去判斷,這無疑額外加重了服務(wù)器的負(fù)擔(dān)。做為優(yōu)化也是我們常見的存儲(chǔ)過程的調(diào)用方法應(yīng)是:
- CallableStatementcstmt=conn.prepareCall("callgetCustomerName(?)");
- cstmt.setLong(1,123);//將值和類型信息編碼后發(fā)送
- ResultSetrs=cstmt.executeQuery();
- //dosomething
JDBC數(shù)據(jù)庫編程5.正確使用Statement和PreparedStatement對(duì)象及其execute方法
Statement 對(duì)象是為僅執(zhí)行一次的查詢語句優(yōu)化而設(shè)計(jì)的,PreparedStatement 對(duì)象是為兩次或更多次執(zhí)行同一查詢語句而設(shè)計(jì)的。PreparedStatement 對(duì)象第一次執(zhí)行一個(gè)準(zhǔn)備好的查詢要花一定的代價(jià),然而它帶來的好處是為以后的查詢加快了速度;因?yàn)镾QL語句已經(jīng)進(jìn)行編譯并放入高速緩存,你可以一直重復(fù)使用;想要改變查詢條件獲得不同的結(jié)果集只需用setXXX方法改變主機(jī)變量(?)的值就行了。
由于PreparedStatement 及 CallableStatement都是Statement的子類,所以它們都有execute(String sql),executeQuery(String sql),executeUpdate(String sql),executeBatch()方法。
execute(String sql)方法返回一個(gè)boolean值,它執(zhí)行任意復(fù)雜的sql語句,可以產(chǎn)生多個(gè)結(jié)果集。如果有結(jié)果產(chǎn)生返回 true,如果沒有結(jié)果集產(chǎn)生或僅是一個(gè)更新記數(shù)則返回 false。它產(chǎn)生的結(jié)果集可以通過getResultSet()和getMoreResults()獲得,更新記數(shù)可通過getUpdateCount()獲得。顯然execute(String sql)方法的使用要復(fù)雜一些,因此如果只是簡單的查詢或更新操作請(qǐng)使用executeQuery(String sql)和executeUpdate(String sql)方法。executeUpdate(String sql)能執(zhí)行INSERT,UPDATE,DELETE語句,及DDL和DML命令(此時(shí)返回值為0)。
如果需要進(jìn)行更多的更新操作,只需將這些更新命令打包后一起提交給數(shù)據(jù)庫,數(shù)據(jù)庫一次處理所有的請(qǐng)求,這比逐條提交要高效得多。例如:
- //保存當(dāng)前提交模式
- booleancommitState=conn.getAutoCommit();
- //關(guān)閉自動(dòng)提交模式
- conn.setAutoCommit(false);
- Statementstmt=conn.createStatement();
【編輯推薦】



















