摘要:本文分析現有的數據庫訪問中間件的現狀,指出其中存在的問題,得出應用新技術的必要性。開發了一個基於Web服務技術的數據庫訪問中間件WSDBM,並以一個應用實例驗證了該中間件的有效性。
關鍵詞:Web服務;數據庫訪問中間件;.Net
1 引言
隨著Intranet/Internet網絡的迅猛發展,面向網絡的分布式數據庫成為支持Internet服務的關鍵,傳統的數據庫訪問技術已漸漸不能滿足分布式應用集成的需要。
【1】利用新技術,研究和開發新的數據庫訪問中間件成為數據庫研究領域的主要方向之一。
Web服務是一種嶄新的分布式計算模型,基於一系列開放的技術標准,其松散耦合、語言中立、平台無關性、開放性使得它將成為下一代電子商務的架構,成為下一代的WWW。
【2】Microsoft.Net提供了基於“.Net框架”的綜合開發平台,它提供了涉及客戶端、服務器和服務的單獨、統一的編程模型。
“.Net框架”和Visual Studio.Net一起,給我們提供了一個完整的應用程序開發平台。
本文主要的工作就是在Visual Studio.Net平台上,利用Web服務將現有的數據庫訪問方式的封裝成中間件,使得封裝後的中間件可以滿足分布式應用的需要。
2 Web服務中間件接口的定義
現有通用的數據庫訪問方式,它的主要操作有:設置數據庫連接,打開和關閉數據庫, 執行查詢和執行其他的Sql語句,實現事務管理和緩沖池管理。比較先進的數據庫訪問方式還支持實時數據庫連接。因此,為了實現對傳統數據庫訪問方式的封裝,我們首先要定義一個Web服務,這個Web服務至少應該擁有以上所列的Web方法(屬性為WebMethod的public函數成員)。這些方法就組成了這個Web服務的接口。
.Net下,Web服務的實現都封裝在System.Web.Services.WebService這個類中。為了實現對數據庫訪問方式的Web服務的封裝,我們必須定義一個新的類,它繼承於WebService或是它的子類。對於相對簡單的Web服務,我們直接讓這個類繼承於WebService。這個生成的類就成了一個具體的Web服務。
.NET中新的關系型數據管理類都是基於類庫中System.Data的一系列的名稱空間,通常稱這些名稱空間集合為ADO.NET。System . Data包含用來訪問和存儲關系型數據的基礎對象。Visual Studio.Net直接給我們提供了System.Data.SqlClient和OleDBClIEnt兩個命名空間,這兩個命名空間分別包含有用來訪問SQL Server關系數據庫和其他關系數據庫所需的基本對象。其中以Transaction結尾的類提供了事務管理的功能,以Connection結尾的類用於連接具體的數據庫。以Command結尾的類定義了對數據庫表的操作。
3 Web服務中間件的實現
3.1實現框架
下面是一個簡單的Web服務中間件來實現(采用Microsoft推薦的c #語言來編寫)。為了實現中間件的可擴展性,我們決定不在中間件的WebMethod(Web方法)中直接實現對數據庫的操作。我們先定義一個虛類DBOperator,在這個虛類中定義了對數據庫操作的接口,包括數據庫的打開(Open)和關閉(Close),事務的開始(BeginTrans)、事務的遞交(CommitTrans)和回滾(RollbackTrans),沒有返回值的Sql語句的執行(void ExecSql)和返回數據集的Sql語句的執行(DataSet ExecSql)。這樣,我們的Web服務中間件的每個WebMethod就僅僅是調用了DBOperator對象的相應的成員函數。比如Web服務中間件中的Open方法就是直接調用DBOperator對象的Open方法。
3 .2具體數據庫操作的實現
為了具體實現對數據庫的操作,我們需要定義DBOperator類的子類,我們以SqlDBOperator為例,顯然SqlDBOperator具體實現了對SQL Server數據庫的操作。
首先定義一個SqlDBOperator類,它繼承於DBOperator,並導入名稱空間System . Data . SqlClIEnt。
using System.Data.SqlClIEnt;
class SqlDBOperator:DBOperator
其次添加私有的數據成員conn,trans,inTransaction,comm
private SqlConnection conn; //數據庫連接
private SqlTransaction trans; //事務處理類
private bool inTransaction=false; //指示當前是否正處於事務中
private SqlCommand comm; //數據庫操作命令處理類
然後我們開始編寫從DBOperator繼承下來的Open操作的實現語句。
public override void Open(string connStr)
{
//如果連接是空的,就先通過connStr構造一個連接
if(conn==null)
conn=SqlConnection(connStr);
//如果這個連接沒有打開,就打開這個連接
if(conn.State.ToString().ToUpper()!="OPEN")
this.conn.Open();
}
在實現了Open(打開數據庫)操作的編寫之後,我們開始編寫Close(關閉數據庫)操作。
public override void Close()
{
//如
事務處理功能的實現:首先是BeginTrans(開始事務)操作的實現。
public override void BeginTrans()
{
//如果連接是空的,則沒有事務可以開始
if(conn==null)
return;
/*開始conn所屬的事務,並將這個事務保存下來,同時設置inTransaction(在事務中)標志為true(真)。表示在進行事務處理*/
trans=conn.BeginTransaction() ;
inTransaction=true;
}
接下來是CommitTrans(遞交事務)操作的實現如下:
public override void CommitTrans()
{
trans.Commit(); //事務遞交
inTransaction=false;//在事務中標志變成false;
}
同理,RollbackTrans(回滾事務)操作的實現如下:
public override void RollbackTrans ()
{
trans.Rollback(); //事務回滾
inTransaction=false;//在事務中標志變成false;
}
最後我們編寫ExecSql(執行Sql語句)操作的實現:
public override void ExeSql(string strSql,string[] strParams,object[] strValues)
{
//如果comm(處理Sql語句的對象)為空,則生成這個對象
if(comm==null)
comm=new SqlCommand();
//設置這個對象的連接conn
comm.Connection=this.conn ;
//判斷是否在事務中,是就設置comm的事務對象屬性
if(inTransaction)
comm.Transaction=trans;
//判斷參數個數和參數值個數是否相等,不等,就不能執行這個Sql語句
if((strParams!=null)&&(strParams.Length!=strValues.Length) )
throw new Exception("查詢參數和值不對應!");
//設置這個comm對象的命令文本
comm.CommandText=strSql;
//將參數名稱和對應的參數值保存到comm的參數數組中
if(strParams!=null)
{
for(int i=0;i<strParams.Length;comm.Parameters.Add(strParams[i],strValues[i]));
}
//執行這個沒有返回值的查詢
comm.ExecuteNonQuery();
}
下面是有返回值的ExecSql操作的實現:
public override DataSet ExeSqlForDataSet(string queryString)
{
//如果comm(處理Sql語句的對象)為空,則生成這個對象
if(comm==null)
comm=new SqlCommand();
//設置這個對象的連接conn
comm.Connection=this.conn ;
//判斷是否在事務中,就是設置comm的事務對象屬性
if(inTransaction)
comm.Transaction=trans;
//生成一個數據集(DataSet)對象(ds),用它來保存返回的查詢結果
DataSet ds = new DataSet();
//定義一個SqlDataAdpater類的對象ad。
SqlDataAdapter ad = new SqlDataAdapter();
//設置這個comm對象的命令文本
comm.CommandText=queryString;
//設置ad的SelectCommand屬性為comm。
//SelectCommand是DataAdapter對象的一個屬性,表示Transact-SQL語句或存儲過程,用於在數據源中選擇記錄。
ad.SelectCommand =comm;
//ad執行fill操作,結果保存到ds中
ad.Fill(ds);
//ds返回
return ds;
}
4 使用已定義的Web服務中間件來訪問數據庫的使用場合
下面我們假設一種該中間件使用的具體情況:
假設有一個私有的比較大型的書店,書店的老板家在離書店有一段距離,在書店和老板家之間架設局域網是不現實的,而老板需要在家裡就可以使用書店的管理系統,甚至進行日常工作的管理。也就是說,老板需要實現在家裡辦公。為此,書店老板決定讓某IT公司開發這個系統。
某IT公司在接到該書店老板提出的開發意向後,在進行初步的系統調研之後,決定接下這個IT訂單,由於這個書店老板並沒有提出具體的解決方案(他也不懂),所以IT公司人員思考了以下幾個開發方案:
在傳統的解決方案中,我們可以采用了動態網頁的編程方法,也就是建立一個網站,這樣,在互聯網的任何地方,我都可以通過這個網站進行訪問,這種實現方法非常優秀,現有的很多公司門戶就是使用了這種技術實現的。但是這種技術有一個缺點是,書店需要有自己的Web服務,這就增加了實現成本。同時這種方案的實現也拋棄了現有的解決方案(書店在建立初期就請某IT公司專門開發一個專用的書店管理系統),拋棄這個Legacy(遺產),重新進行設計,書店老板也不願意。
另一個傳統的解決方案是利用Corba或DCOM進行編程。原有系統就是利用Visual C++進行編程的。所以可以選擇DCOM進行編程,這也非常合理。但是這個方案限制了實現的平台,同時開發費用較高,畢竟利用DCOM進行編程開發和實現是一件比較復雜的工作。
最後,公司決定利用Web服務技術封裝原有的數據庫訪問層,這樣我們的客戶端僅需要進行數據庫訪問層的修改。這樣,系統原來的界面不便,Business層(業務層)不變,改變的僅僅是客戶端的的數據庫訪問層的實現。以上就是這個Web服務使用的具體場合。
下面我們在Visual Studio.Net平台上利用c# Windows應用程序編程項目來說明該Web服務的使用。
首先新建一個C# Windows應用程序項目,在窗體上添加控件,一個DataGrid和一個按鈕。
然後添加Web引用,將該Web服務中間件所在的asmx文件地址添加到Web引用中。這樣我們就可以直接使用這個服務了。
雙擊按鈕1,編程如下:
//新建一個Web服務的實例
WebReference.ServiceWSDBM the=new WindowsApplication1.WebReference.ServiceWSDBM();
//以數據庫連接字符串為參數,打開上面的連接字符串所可以連接的數據庫
the.Open("Provider=SQLOLEDB.1;Persist Security Info=False;User ID=sa;Initial Catalog=Northwind;Use Procedure for Prepare=1;Auto Translate=True;Packet Size=4096;Use Encryption for Data=False;Tag with column collation when possible=False");
the.Open();
//對已經打開的數據庫進行查詢操作,返回記錄集。
System.Data.DataSet ds=the.exeSqlForDataSet("select * from products");
//將查詢得到的記錄集顯示在DataGrid中
dataGrid1.DataSource=ds;
dataGrid1.DataMember=ds.Tables[0].TableName;
//關閉這個連接
the.Close();
執行結果,在DataGrid中將顯示出連接上的SQL Server庫中的products表中的內容。
5 結束語
根據以上的介紹,基於Web服務實現的數據庫訪問中間件,可以擴展數據庫系統的應用范圍,這種中間件不僅適應於局域網,更加適應於未來的基於廣域網的應用程序。這個中間件於傳統中間件相比有以下優點: 1)跨平台。2)使用方便,可以將這個Web服務可以象本地組件一樣被應用。3)兼容性強,擴展方便,比如我們想要增加對Oracle的支持,僅需下載和Oracle有關的.Net插件(下載地址:可到http://msdn.microsoft.com/downloads/上下載.Net Framework Data Provider for Oracle),然後將上述程序中的Sql替換為Oracle即可。綜上所述,基於Web服務實現數據庫訪問中間件將是一種比較有效的解決方案。