設計模式在Java數據庫編程中的運用


JDBC技術是Java語言中數據庫編程的標準,近年來隨着B/S應用的廣泛興起,Java技術在目前的服務器端越來越受重用。作爲信息系統中關鍵的一部分,數據庫編程是編程人員必須掌握的一部分。JDBC技術本身提供了一些可用的編程接口來完成一些基礎事務的處理,但我們也發現,如果只是單純地使用JDBC規範中提供的編程接口來完成事務邏輯的話,代碼的冗餘度十分高,編程效率也很低。基於此,如果在底層接口的基礎之上,運用適當的設計模式進行抽象封裝,並加以一些特定的設計以後,就會在JDBC規範接口之上形成一個可擴展的框架。在這個抽象層次上進行開發,不論是重用性、可靠性,還是開發效率,都會大大提高。
1.設計模式要點
所謂模式,就是對特定情形下特定問題的解決方案。這些方案,往往是經驗的總結,是公認優秀的。設計模式就是在面向對象軟件設計時對特定場景下特定問題的公認優秀的設計方案。面向對象思想出現這麼多年,現在已經有了好多特定的模式值得我們在設計軟件時遇到大多數問題時參考借鑑。
2.JDBC編程的要點
利用JDBC標準提供的接口,如果要進行數據庫的訪問,一般的編程過程如下:
(1)獲取數據庫的連接。
(2)對取得的連接的進行特定SQL語句的操作。
如果每次對數據庫訪問都單單進行以上的操作過程,而不進行一定的組織設計,那麼代碼的冗餘度將會十分高,程序員的工作量也十分大,並且編寫出來的代碼也很不靈活,因此有必要引入一定的設計模式來提高代碼的可複用度與可擴展性。
3.利用Factory Method模式控制數據庫連接的產生
在實際的已經確定的系統中,數據庫往往是很少變化的,所以獲取數據庫的第一步在幾乎所有的訪問中都是相同的,爲了提高複用度,有必要把它提取成一個單獨的模塊。在這裏,只可以使用Factory Method來封裝產生數據庫連接操作。考慮到連接的頻繁性,沒有必要每次要求訪問數據庫都對數據庫申請產生連接,我們可以使用連接池技術來管理一定數量的數據庫連接,這裏我們定義一個ConnectionPool類,其產生數據庫連接的操作定義爲newConnection()。
以下是Factory Method基本的代碼片斷:
public class ConnectionPool……
private Connection newConnection() {
……
Connection con = DriverManager.getConnection(URL, user, password);
……
return con;
  }
4.利用Singleton模式來控制連接池對象的惟一性
我們已經有了管理數據庫連接的連接池類ConnectionPool,但要注意一點:連接池對象在系統運行時應該是惟一的。原因很簡單,如果不惟一的話,對不同的數據庫訪問產生不同的連接池對象,那麼連接池對象的作用就根本沒有起。當然,也可以在程序中只創建一個連接池對象,但這不能保證別的程序員也能做到這一點,這時,應該採用singleton模式,通過getInstance()方法獲取惟一的連接池對象。
public class ConnectionPool……
public class ConnectionPool {
  private static ConnectionPool instance = null;
  public static synchronized ConnectionPool getInstance() {
  if (instance==null)
    instance=new ConnectionPool ();
return instance;
  }
  private ConnectionPool () {
  ……
  }
  }
  
到這裏,要產生數據庫連接的任務已經完成了。
5.利用Template Method模式來提取操作框架
對數據庫的操作可以分爲兩類:對於第一類操作,會產生一定的結果集,如查詢數據庫;另一類操作,則只是對原有的數據庫的變更,不會產生結果集,比如插入操作、更新操作。對於這兩種情況,我們可以分別封裝成相應的類。但我們發現,這兩個類在操作時有很多的相同點。基本流程都是先獲取數據庫連接,然後生成Statement對象,再在這個Statement對象上調用方法執行SQL語句,這些步驟可以提取成一個方法execute()到一個父類裏面,可稱爲DbBean類。這個父類只用公佈出一個方法讓子類去重載,這種方法往往被稱爲勾子方法,在這裏不妨稱爲executeSql()。有了這個父類,對於兩種不同的操作類型,會產生兩個子類,不妨稱爲SelectBean與UpdateBean。對於不同的子類,只是重載父類中的勾子方法executeSql(),執行不同的數據庫訪問,不用去關心準備這個訪問所要做的事。
6.引入Adapter模式來解決已有接口的不一致
在JDBC提供的接口裏面,對數據庫訪問的方法分別爲executeQuery()與executeUpdate(),在以上引入Template Method模式後,得在子類中去重載父類中公佈出來的勾子方法executeSql(),這個勾子方法的名字是惟一的,這樣,爲了讓我們的特定數據庫訪問能很好地銜接上去,我們可以引入Adapter模式,把這兩個不同的方法適配成executeSql()。注意,因爲executeQuery()方法有一個返回值,我們有必要在包含它的子類裏面加上一個ResultSet類的成員變量rs。這樣,在executeSql()方法裏面,只要把executeQuery()的返回值賦給rs就可以了。圖1是引入以上兩個模式後形成的框架圖。
7.引入Facade模式使操作接口更接近業務邏輯
在對數據庫查詢時,使用JDBC已經提供的接口executeQuery()時,返回給我們的是一個ResultSet對象,裏面依次存放着要查詢的每一列。程序員如果要獲取所需的信息,往往得通過調用返回對象的getObject(int i)方法。這樣做,一方面,很不直觀,另一方面,代碼的耦合性很高。對此,我們想到了引入Adaptor模式,這樣可使我們的接口更進一步脫離數據庫操作,從而可更關注業務邏輯。
假設現在有一個學生信息表T_Student,裏面的信息爲ID,Name,Age,其基本表結構如下:
對於這個表的查詢,我們的目的就是能用getId(),getName(),getAge()這樣的方法來獲取數據。基於這樣的目的,現在要做的就是把查詢所得到的數據如何正確地定位到我們方法的返回值。對於數據庫查詢,我們發現,在查詢語句中要查詢的記錄的序號與返回結果中的序號是一一對應的,利用這一點,可以把要查詢的字段名放在一個Vector裏面,如上面Vector中的內容可以是(“Id”,“Name”,“Age”),我們要執行的SQL語句很容易通過這些字段名來拼接,其執行結果是按給出的順序放在ResultSet對象裏面的。最後,對於特定的函數調用,如getId(),可以通過Java提供的Reflection機制獲取函數名,然後去掉前面的get字符,再在字段名Vector裏用indexOf(Object o)方法獲取字段名所對應的序號index,這也是其查詢結果ResultSet裏的序號,通過它可以從查詢結果ResultSet裏面通過getObject(index)得到我們要的結果。我們可以把這些不變的代碼提取到父類SelectBean中,這樣做的好處是以後對於不同的表結構可以生成相應的子類。我們只用定義一個Vector變量,放上我們要查詢的字段名字符串,並定義相應的get函數。當我們調用它們時,只需調用以上父類的公共匹配代碼,即可獲得正確的數據。以下是針對以上表結構引入Facade模式後的效果圖與代碼片斷:
……
String name,id,age;
StudentSelect student = new StudentSelect();
student.execute();
name =student.getName();
id =student.getId();
age= student.getAge()
……
對於對數據庫更新的SQL語句,也可利用以上的機制,做法是類似的,在此不再贅述。
本文提供了在Java數據庫編程中引入設計模式的一個思路。在實際中,我們基於以上的設計思路實現了一個框架,基於這個框架,編寫Java數據軟件的效率大大提高。當然,本文提供了一個整體的設計思路,在實際中,可以根據特定的情況,修改其中的一些模塊,比如,數據庫的連接可以從J2EE中的數據源獲取。對此,讀者可以自行取捨。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章