使用設計模式構建通用資料庫訪問類 (轉)

gugu99發表於2007-08-16
使用設計模式構建通用資料庫訪問類 (轉)[@more@]使用設計構建通用訪問類
作者:孫亞民  本文選自:賽迪網 年03月20日
  在應用的設計中,資料庫的訪問是非常重要的,我們通常需要將對資料庫的訪問集中起來,以保證良好的封裝性和可維護性。在中,資料庫的訪問,對於自家的Server和其他資料庫(支援Ole),採用不同的訪問方法,這些類分別分佈於System.Data.SqlClient和System.Data.OleDb名稱空間中。微軟後來又推出了專門用於訪問資料庫的類庫。我們希望在編寫應用的時候,不因這麼多類的不同而受到影響,能夠儘量做到資料庫無關,當後臺資料庫發生變更的時候,不需要更改客戶端的程式碼。

  有的時候,為了和其他原因,我們也希望提供對資料庫訪問的快取,特別是資料庫連線的快取。雖然微軟給我們內建了資料庫快取,但是,自己控制快取,無疑可以提供更大的靈活性和。

  這就需要我們在實際開發過程中將這些資料庫訪問類再作一次封裝。這裡,介紹一種在實際應用中得到了非常好的效果的實作策略。Factory和Silgleton設計模式是使用的主要方法。

  我們先來看看Factory的含義:定義一個用於建立的介面,讓子類決定例項化哪一個類。Factory Method使一個類的例項化延遲到其子類。我們這裡可能會處理對多種資料庫的操作,因此,需要首先定義一個操縱資料庫的介面,然後,根據資料庫的不同,由類工廠決定例項化哪個類。

  下面,我們首先來定義這個訪問介面。為了方便說明問題,我們為這個類定義了比較少的方法,其他的方法是很容易參照新增的。同時注意,我這裡使用了abstract class來定義這個訪問介面,而不是interface,理由在後面可以看到。

public abstract class DBOperator { public abstract IDbConnection Connection{get;} //得到資料庫連線 public abstract void Open(); //開啟資料庫連線 public abstract void Close(); //關閉資料庫連線 public abstract void BeginTrans(); //開始一個事務 public abstract void CommitTrans(); //提交一個事務 public abstract void RollbackTrans(); //回滾一個事務 public abstract void exeSql(string strSql,string[] strParams,[] objValues); //Sql語句,沒有返回值 public abstract DataSet exeSqlForDataSet(string QueryString);//執行Sql,返回DataSet }



  然後,我們分別為和OleDb資料庫編寫兩個資料訪問的具體實現類:

  Sql Server的資料庫訪問類:

internal class SqlDBOperator: DBOperator { private SqlConnection conn; //資料庫連線 private SqlTransaction trans; //事務處理類 private bool inTransaction=false; //指示當前是否正處於事務中 public overr IDbConnection Connection {   get{return this.conn;} } public SqlDBOperator(string strConnection) {   this.conn= new SqlConnection(strConnection); } public override void Open() {   if(conn.State.ToString().ToUpper()!="OPEN")      this.conn.Open(); } public override void Close() {   if (conn.State.ToString().ToUpper()=="OPEN") this.conn.Close(); } public override void BeginTrans() {   trans=conn.BeginTransaction() ;     inTransaction=true; } public override void CommitTrans() {   trans.Commit();     inTransaction=false; } public override void RollbackTrans() {   trans.Rollback();     inTransaction=false; } public override void exeSql(string strSql,string[] strParams,object[] strValues) {   SqlCommand cmd=new SqlCommand();   cmd.Connection=this.conn ;   if(inTransaction)     cmd.Transaction=trans;   if((strParams!=null)&&(strParams.Length!=strValues.Length) ) throw new ParamValueNotMatchException("查詢引數和值不對應!"); cmd.CommandText=strSql;   if(strParams!=null) {   for(int i=0;i



  OleDb資料庫操作的類同Sql Server資料庫操作的類非常相似,只是把相應的Sql類替換成OleDb類。需要注意的是,因為OleDb和Sql Server的引數傳遞方式不一致,所以,這裡需要做一點小小的轉換,將"@引數名"型別的引數轉換成"?",這個細節希望讀者能夠注意到。程式碼如下:

internal class OleDBOperator : DBOperator { private OleDbConnection conn; private OleDbTransaction trans; private bool inTransaction=false; public OleDBOperator(string strConnection) {  this.conn= new OleDbConnection(strConnection); } public override IDbConnection Connection {  get{return this.conn;} } public override void Open() { if(conn.State.ToString().ToUpper()!="OPEN") this.conn.Open(); } public override void Close() {   if (conn.State.ToString().ToUpper()=="OPEN") this.conn.Close(); } public override void BeginTrans() {   trans=conn.BeginTransaction() ;    inTransaction=true; } public override void CommitTrans() {   trans.Commit();   inTransaction=false; } public override void RollbackTrans() {   trans.Rollback();   inTransaction=false; } public override void exeSql(string strSql,string[] strParams,object[] strValues) { OleDbCommand cmd=new OleDbCommand();   cmd.Connection=this.conn ; if(inTransaction)   cmd.Transaction=trans; if((strParams!=null)&&(strParams.Length!=strValues.Length) ) throw new ParamValueNotMatchException("查詢引數和值不對應!"); cmd.CommandText=this.ChangeQueryString(strSql); if(strParams!=null) { for(int i=0;i



  現在我們已經完成了所要的功能,下面,我們需要建立一個Factory類,來實現自動資料庫切換的管理。這個類很簡單,主要的功能就是根據資料庫連線字串,判斷使用什麼資料庫,然後,返回適當的資料庫操縱類。在這裡,判斷的方法很簡單,只是根據兩種資料庫連線字串的不同來判斷。在實際中,隨著資料庫類的增加,判斷的方法可能會有所變化,讀者應當根據自己的實際情況來做相應的調整。

public class DBOperatorFactory { public static DBOperator GetDBOperator(string strConnection) {   if(strConnection.IndexOf("provider=")<0) //SqlServer {   return new SqlDBOperator(strConnection); }   else //other database {   return new OleDBOperator(strConnection); } } }



  好了,現在,一切都完成了,客戶端在程式碼的時候,可能就是採用如下形式:

DBOperator db=DBOperatorFactory.GetDBOperator(strConnection) db.Open(); db.需要的操作 db.Close(); 或者: DBOperator db=DBOperatorFactory.GetDBOperator(strConnection) db.Open();db.BeginTrans(); try { db.需要的操作 db.CommitTrans(); } catch { db.RollbackTrans(); } db.Close();



  當資料庫發生變化的時候,DBOperatorFactory會根據資料庫連線字串自動呼叫相應的類,客戶端不會感覺到變化,也不用去關心。這樣,實現了良好的封裝性。當然,前提是,你在編寫程式的時候,沒有用到特定資料庫的特性,例如,Sql Server的專用。

  實際上,Factory模式也可以不使用Factory類來實現,而是讓介面抽象類自己來管理,這可以稱作自管理的Factory,是Factory模式的一種變形。這麼做的好處,是可以免去一個Factory類,使程式碼更加簡練。這麼做,我們需要對DBOperator類做一些改變,增加一個Instance方法。這也是對DBOperator採用抽象類而不是介面的原因(介面的方法不能有實現),程式碼如下:

public static DBOperator Instance(string strConnection) { if(strConnection.IndexOf("provider=")<0) //SqlServer { return new SqlDBOperator(strConnection); } else //other database { return new OleDBOperator(strConnection); } }



  然後,客戶端程式碼就可能是類似於下面的形式:

DBOperator db= DBOperator.Instance(strConnection) db.Open(); db.需要的操作 db.Close();



  下面來看看連線池的做法,方法就是Singleton。

  先看Singleton模式的經典含義:保證一個類僅有一個例項,並提供一個訪問它的全域性訪問點。推而廣之,當我們需要精確控制類在系統中的例項的個數的時候,就可以使用Singleton模式。現在,我們需要構建一個緩衝池,儲存資料庫類的例項,正好是Singleton模式發揮作用的時候。

  我們仍然讓DBOperator類自己來管理這個緩衝池,為了實現這個目的,我們需要對DBOperator類做一些變化:

  首先,增加兩個變數:

 static DBOperator[] ConnectionPool=new DBOperator[int.Parse(ConfigurationSettings.AppSettings["PoolCount"])];  static int CurrentPosition=-1;



  然後,對Instance方法做一些改變:

public static DBOperator Instance(string strConnection) { if(ApplicationConfiguration.PooledConnectionCount<1) //沒有緩衝 { return CreateNewDBOperator(strConnection); } else { CurrentPosition++; if(CurrentPosition==ApplicationConfiguration.PooledConnectionCount) CurrentPosition=0; if(ConnectionPool[CurrentPosition]==null) { ConnectionPool[CurrentPosition]=CreateNewDBOperator(strConnection); } return ConnectionPool[CurrentPosition]; } } private static DBOperator CreateNewDBOperator(string strConnection) { if(strConnection.IndexOf("provider=")<0) //SqlServer { return new SqlDBOperator(strConnection); } else //other database { return new OleDBOperator(strConnection); } }



  這裡使用的演算法比較簡單,只是為了能夠比較清楚地說明問題,讀者應當能夠在實際使用過程中,實現更好的演算法。

  以上,介紹了一種通用資料庫操作類的實現設計方法,希望能夠對大家有所啟發。筆者設計sh的時候,在資料庫處理層,採用了上面的方法,取得了很好的效果。



  作者:孫亞民,畢業於南京大學,中國科技大學技術在讀研究生,熟悉和.Net平臺,蘇州某公司技術總監,基於.Net平臺的Websharp中介軟體的設計者。可以透過 sunny_y_m@163.聯絡。


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10748419/viewspace-961000/,如需轉載,請註明出處,否則將追究法律責任。

相關文章