Java之路(5)--差不多該開始操作數據庫了吧

笑着 胖胖蘭原創,轉載請註明。<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />

    [email protected]

 http://blog.csdn.net/bluesmile979/archive/2008/10/21/3118083.aspx

    前面幾篇文章講的東西的理解消化,加上對應的基礎內容學習,如果沒有基礎的話大概需要3個月左右。心急吃不了熱豆腐。不要着急。如果前面的都學好了。那麼差不多要接觸一個比較重要的東西--數據庫操作了。笑着在這一篇文章裏要談的,是關於數據庫操作的一些注意事項。

 

   首先來看一下Java中最基本的數據庫連結程序。

    Class.forName("oracle.jdbc.driver.OracleDriver").newInstance();  

String url="jdbc:oracle:thin:@localhost:1521:dbName";

String user="bluesmile";

String password="xiaozhe";

Connection conn= DriverManager.getConnection(url,user,password);  

Statement stmt=conn.createStatement(***,***);  

String sql="select * from test";  

ResultSet rs=stmt.executeQuery(sql);  

while(rs.next()) {  

      String s = rs.getString(1);

      System.out.println("您取到的數據爲:" + s);

}    

rs.close();  

stmt.close();  

conn.close();  

 

當然,如果就用這樣的程序來做數據庫連結操作,那時有很多問題的。這裏我們只是通過這一段程序來看一下數據庫操作的基本流程。具體使用這樣的一段程序有什麼問題,就是笑着這一篇文章要談的。

 

那麼先來看一下數據庫操作的基本流程。

1. 取得數據庫連接對象Connection

2. 取得SQL語句執行對象

3. 創建SQL語句並執行

4. 從返回結果ResultSet中取得需要的數據

5. 關閉被打開的資源。

以上,是數據庫操作的最最基本的流程,最少最少的,我們也要實現上面流程中的操作。問題,也是就是從如何實現這些基本流程開始的。

 

1. 關於如何取得數據庫連結對象Connection

a.      關於針對連接對象的參數設定

通常我們採用的方法是DriverManager.getConnection(url,user,password);來取得Connection對象。在這裏很多參數都是採用的默認的。比如oracle數據庫對應有兩個對性能影響比較大的參數defaultRowPreFetchdefaultBatchValue,前一個設定每次從數據庫讀取的數據條數,後一個用來設定SQL執行對象Statement的批處理執行語句條數。這兩參數的默認值笑着記得都是1,這無疑增加了我們跟數據庫打交道的次數。所以明確設定比較好。針對Connection的設定根據數據庫不同會有所不同,具體可以取研究對應的實現了Connection接口的實際針對該數據庫的連接對象,比如Oracle對應的OraclConnection(記不清楚了,好像叫做這個名字)。不同的數據庫提供的JDBC Driver裏面都會有這樣的具體的Connection實現類的。這些具體的實現類會提供參數的設定接口。這裏只能夠提個醒,具體哪些參數,如何設定,需要的時候要心裏有數,自己去研究一下。

 

b.      關於數據庫連結池

創建Connection對象一般來說開銷是比較大的。每次連接都創建新的對象顯然不是一個很好的做法。幸運的是大多數數據庫應用服務器都提供了數據庫連結池。笑着在這裏要強調的是,我們可能沒有必要去做連結池的具體操作,設定。但是我們必須要明白它的存在,我們的腦海裏面要有連結池,緩衝池這樣的概念,也許大多數情況下,數據庫連結池不要要我們做什麼,甚至不需要我們知道他的存在,但是,實際程序中有很多影響效率的地方,池,也許會幫你解決一些問題。

所謂池的策略,簡單來說,當你請求一個資源,池會看看池中有沒有資源,有的話把這個資源分發給請求,沒有的話,生成新的資源同時把該資源放到池中。當請求歸還的時候,池會判斷池中是否滿了,如果滿了,那麼釋放該資源。其中關鍵的,就是生成新資源,判斷是否釋放資源,以及如何維護池中資源的策略,算法。

 

c.       關於設定AutoCommit

Java裏面數據庫的AutoCommit的默認設定是true。什麼意思呢?就是我每執行一個SQL語句就會向數據庫提交一次,數據庫就要實際產生一次動作,這比批量的向數據庫提交SQL語句的效率要差一些。尤其在批量處理insert,update語句的時候。效率差別還是很明顯的。而且,你無法在某一句sql語句失敗的時候rollback,所以,要適當考慮設定autocommitfalse,自己主動在適當的時候commit。因爲Java中默認爲true,可能很多人會忘記考慮這個事情。至少,爲false的時候你的數據在你明確commit之前不會被保存到數據庫中,那麼要不要自動commit至少我們不會忘。不知道Java裏面爲什麼默認值設定爲了true了。

 

2. 關於SQL語句執行對象

Java中存在Statement,PreparedStatement,CallableStatement三種SQL語句連接對象,一般來說,比較常用的是PreparedStatement,下面簡單說說他們的區別。

 

來看一下最簡單的SQL語句,select * from table where a=b

 

大家考慮一下,數據庫查詢的時候,數據庫軟件要如何判斷我們要做什麼呢。

恩,是的,數據庫軟件需要解析我們傳給他的這個SQL語句的字符串,看看select後面是什麼,from後面是什麼,where 後面是什麼。就是說數據庫軟件要解析Key:Value。那麼這個解析過程是要花時間的,越複雜的SQL語句需要花費的時間就越多。

 

是的,這就是StatementPreparedStatement之間的區別,Statement要針對我們傳入的每一條SQL語句進行解析,而PreparedStatement採用?這個符號來匹配變化的值,那麼當inserupdateSQL語句中大部分內容相同的時候,採用?這個符號來匹配少量變化的值,數據庫軟件就只需要對這個SQL語句解析一次,然後等待接受PreparedStatement後續傳入的可變值部分。所以,我們常用的是PreparedStatement

 

至於CallableStatement,是調用存儲過程的,需要在數據庫服務期端的存儲過程相配合。因爲使用了服務期端的存儲過程,那麼效率自然就高一些。笑着沒用過,不好說什麼。但是有一點,存儲過程執行本身,因爲它就是在數據庫服務器端運行,數據庫對其也有相當的優化,本身執行速度那肯定是快的。但是Java調用存儲過程,這個調用過程本身也是要花時間的。所以到底快不快是不一定的。

另外,是用SQL執行對象的addBatch,executBatch方法回比直接使用executeQuery的效率好一些。

附:常用用法代示例

a.      Statement

Stmt.addBatch(“insert…..”);

Stmt.addBatch(“update….”);

Stmt.executeBatch();

b.      PreparedStatement

3. 關於創建的SQL語句

SQL語句本身是支持相當多的邏輯判斷,數據篩選的,要適當的使用SQL語句本身的功能。比如Select * From table 然後再通過Java程序篩選需要的數據,那就不如直接使用Select * From table Where a=b讓數據庫來幫忙篩選。

 

基本原則,我們要減少跟數據庫之間的通信量。這根IO是同樣的道理,程序根數據庫,IO打交道,無論是建立連接,還是數據通信,都是需要花比較多的時間的,所以我們要儘量減少這樣的操作

 

4. 關於ResultSet

a.      參數設定,ResultSet裏面有fetchSize,FetchDirection這樣的參數,fetchSize參考Connection時候的說明,意思差不多。fecthDirection是設定遊標運行方向的。簡單來說就是數據結構中的鏈表,單向鏈表遊標就只能一直向前,雙向鏈表可以向前也可以向後移動,但是同時自然要增加一些控制用的東西,影響效率。也就是說沒有必要的話就是用一直向前這種就可以了,這也是Java默認的設定。

 

b.      關於從ResultSet中取值

 

Java裏提供兩種方法,一種是使用字段位置Index作爲參數,一種是使用字段名稱ColName作爲參數,那麼自然是用Index會快一些,但是笑着測試這個效率影響不是很大,用Index不方便程序閱讀。到底用什麼辦法還是大家自己根據具體情況判斷吧。用Index的話注意把註釋加加好。笑着還是傾向這種方法的。

 

5. 關閉資源。

本來關於關閉資源沒啥好說的。但是看到網上大量的演示程序給出的代碼稍微有些問題,所以還是提一下。基本原則就是你必須要保證你的資源被關閉,被釋放掉了。本文開始的程序那樣做的話,中間任何語句產生異常的話,這一份資源就不會被釋放掉了,那麼你的CPU佔用率達到100%指日可待。正確用法如下,不多解釋了。

try{

} catch (){

} finally{

    if(rs != null){

   try(){

    rs.close();

} catch() {

}

}

    // 以下略

}

6. 再說說基本原則

前面提到了一個基本原則,我們要減少跟數據庫之間的通信量。這根IO是同樣的道理,程序根數據庫,IO打交道,無論是建立連接,還是數據通信,都是需要花比較多的時間的,所以我們要儘量減少這樣的操作。

 

這裏數據庫也好,IO也好,爲了減少建立連接,數據通信的次數的具體的辦法。都是儘量把有用的,常用的數據保存在內存中,類似池,緩衝的概念,但是什麼事情都有個度。過猶不及,用IO打個比方。一般屬性文件內容比較少,程序中經常要使用,我們可以一次性的讀取到內存中。但是並不一定所有的文件都適合一次性全都讀到內存中。比如文件內容很多的時候。一方面內存開銷太大了,空間方面我們也要考慮。而且過多的沒有用的信息放在內存裏,也是沒有價值的。就是說雖然可以空間換時間,也要我們在掌握了基本原則的基礎之上,根據具體情況來作出不同的判斷。萬事都沒有絕對的。

 

7.

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章