天天看點

ADO.NET架構

2010年7月18日記

ADO.NET架構

1、使用ADO.NET連接配接最佳練習

2、使用ADO.NET指令最佳練習

3、使用DataReader、DataSet、DataAdapter

4、使用ADO.NET的其他技巧

1、Data Provider

SQL Server Provider

SqlConnection/SqlCommand/SqlDataAdapter/SqlDataReader

OleDbProvider

OleDbConnection/OleDbCommand/OleDbDataAdapter/OleDbDataReader

2、DataSet

DataTable

DataColumn

DataRow

Constraints

DataRelation

3、Data use application

Windows Form

Web Form

Others

1、資料提供程式:

SQL Server .NET資料提供程式

OLE DB.NET資料提供程式

ODBC .NET資料提供程式

基于Oracle的.NET資料提供程式

2、對象概述

Connection類:在代碼和容納資料的資料存儲之間提供了基本的連接配接

Command類:用于描述SQL語句或者通過其Connection類執行的存儲過程

DataReader類:從資料源中擷取隻讀的資料流

DataAdapter類:功能最強大、更複雜的對象,可以讀取、改變資料源

ADO.NET連接配接最佳練習

1、使用連接配接池

用DataAdapter優化連接配接

始終關閉Connection和DataReader

在C#中使用“Using”語句

異常處理

安全連接配接

2、為什麼使用連接配接池?

建立連接配接所發費的時間與資源并不是無價值的

Connection pools可以使在特定頁面運作過後,連接配接能夠保持下來

3、使用連接配接池和不使用連接配接池的對比

(1、使用連接配接池:在連接配接池中,判斷是否已有連接配接?

沒有連接配接,那麼建立資料連接配接,然後向資料庫發送查詢請求,将傳回的資料顯示,最後斷開連接配接

如果連接配接池中已有連接配接,那麼直接向資料庫發送查詢請求,将傳回的資料顯示,最後斷開連接配接

(2、不使用連接配接池:直接建立資料連接配接,然後向資料庫發送查詢請求,将傳回的資料顯示,最後斷開連接配接

顯然,連接配接池減少了資料連接配接上的性能消耗,效率肯定比不使用連接配接池高

4、ADO.NET中的連接配接池

如果使用的是OleDbConnection類,則連接配接池将由提供程式自動處理,而不必自己進行管理。

如果使用的是SqlConnection類,則連接配接池被隐式管理,但也提供選項允許自己管理連接配接池。

在連接配接池字元串中指定:

Pooling=true;//預設為true

Connection lifetime=5; //預設為0

Min pool size=1; //預設為0

Max pool size=50; //預設為100

1、DataAdapter的Fill和Upadate方法在連接配接關閉的情況下自動打開為相關指令屬性指定的連接配接。如果Fill或者Update方法打開了連接配接,Fill或者Update将在操作完成的時候關閉它。為了獲得最佳性能,僅在需要時将與資料庫的連接配接保持為打開,同時,減少打開和關閉多操作連接配接的次數。

2、如果隻執行單個的Fill獲Update方法調用,建議允許Fill獲Update方法隐式打開和關閉連接配接。如果對Fill和/或Update調用很多,建議顯示打開連接配接,調用Fill和/或Update,然後顯示關閉連接配接。

3、始終關閉Connection和DataReader

完成對Connection或DataReader對象的使用後,總是顯示地關閉它們。盡管垃圾回收最終會清除對象并釋放連接配接和其他委托資源,但垃圾回收僅在需要時執行。

4、在C#中是偶那個“Using”語句

Using語句在離開自己的作用範圍時,會自動調用被“使用”的對象的Dispose。

連接配接異常

1、DataException類:表示使用ADO.NET元件發生錯誤時引發的異常

2、DBConcurrencyException類:在更新操作過程中受影響的行數等于0時,由DataAdapter所引發的異常。

3、SqlException類:當SQL Server傳回警告或錯誤時引發的異常。無法繼承此類。

屬性

任何時候隻要SQL Server.NET資料提供程式遇到伺服器生成的錯誤,就會建立該類。SqlException始終包含至少一個SqlError執行個體。

1、嚴重程度等于或者小于10的消息是資訊性消息,它們訓示由使用者輸入資訊中的錯誤所導緻的問題。嚴重程度11至16的消息是由使用者生成的,可以由使用者更正。嚴重程度17、18或19的錯誤時,雖然可能無法執行特定語句,但仍可以繼續工作。

2、當嚴重程度等于或者小于19時,SqlConnection保持打開狀态。當嚴重程度等于或大于20時,伺服器通常會關閉SqlConnection。但是,使用者可以重新打開連接配接并繼續操作。在這兩種情況下,執行指令的方法都會生成SqlException。

Private void btnTest_Click(object sender,System.EventArgs e)

{

string strConUnusePool=”Server=localhost;Integrated Security-SSPI;database=mydatabase;pooling=false”;

string strConusePool=”Server=localhost;Integrated Security=SSPI;database=mydatabase;”

+”pooling=true;connction lifetime=5;”;

Int nConNum=50;

//計算不使用連接配接池建立連接配接的時間

DateTime dtStart=DateTime.Now;

for(int i=1;i<=nConNum;i++)

Using(SqlConnection con=new SqlConnection(strConUnusePool))

{con.Open();con.Close();}

}

DateTime dtEnd=DateTime.Now;

TimeSpan ts=dtEnd-dtStart;

lbUnUse.Text=ts.Milliseconds.ToString();

//計算使用連接配接池的時間

dtStart=DateTime.Now;

Using(SqlConnection con=new SqlConnection(strConusePool))

dtEnd=DateTime.Now;

ts=dtEnd-dtStart;

lbUse.Text=ts.Milliseconds.ToString();

Private void btnScurity_Click(object sender,System.EventArgs e)

String strCon=”server=(local);database=mydatabase;uid=sa;pwd=111;pooling=false;”;

SqlConnection con=new SqlConnection(strCon);

String strSql=”select * from ScoreTable where UserName=’”+tbUserName.Text.Replace(“’”,”””);

SqlCommand com=new SqlCommand(strSql,con);

con.Open();

SqlDataReader sdr=com.ExecuteReader();

if(sdr.Read())

MessagerBox.Show(“Authenticated”);

else

MessageBox.Show(“Invalid User”);

sdr.Close();

con.Close();

使用指令最佳練習

1、Command對象的使用

使用SqlCommand的最佳練習

使用Prepare方法

顯示指定架構和中繼資料

測試Null

把Null作為參數值傳遞

執行事務

Command對象的使用

2、方法和描述

Cancel:取消資料指令的執行

CreateParameter:建立一個新的參數

ExecuteNonQuery:執行指令并傳回受影響的行數

ExecuteReader;執行指令并傳回生成的DataReader

ExecuteScalar:執行查詢并傳回結果集中的第一行的第一列

ExecuteXmlReader:執行指令并傳回生成的XMLReader

Prepare:在資料源上建立一個準備好的指令版本

ResetCommandTimeOut:将CommandTimeOut屬性重置為預設值

3、DataReader

當資料指令傳回結果集時,用DataReader來檢索資料

DataReader對象傳回一個來自資料指令的隻讀的、隻能向前的資料流

記憶體中每次僅有一行資料行,是以開銷很少。

4、ExecuteScalar和ExecuteNonQuery

如果想傳回像Count(*)、Sum(Price)或Avg(Quantity)的結果那樣的單值,可以使用Command.ExecuteScalar。

因為單獨一步就能完成,是以ExecuteScalar不僅簡化了代碼,還提高了性能;要是使用DataReader就需要兩步才能完成(即,ExecuteReader+取值)。

使用不傳回行的SQL語句時,例如修改資料(例如INSERT、UPDATE或DELETE)或僅傳回輸出參數或傳回值,請使用ExecuteNonQuery。這避免了用于建立空DataReader的任何不必要處理。

5、使用SqlCommand的最佳練習

存儲過程是SQLServer資料庫的一個重要特色

存儲過程執行效率比SQL文本指令要高得多

提高了程式的複雜性

存儲過程中可以使用變量和條件

可以在存儲過程中使用參數

如果調用存儲過程,将SqlCommand的CommandType屬性指定為StoredProcedure的CommandType。這樣通過将該指令顯示辨別為存儲過程,就不需要在執行之前分析指令。

對于重複作用與資料源的參數化指令,Command.Prepare方法能提高性能。

對于一些資料源(例如SQL Server 2000),指令是隐式優化的,不必調用Prepare。

對于其他(例如SQLServer7.0)資料源,Prepare會比較有效。

1、測試Null:

如果表(在資料庫中)中的列允許為空,就不能測試參數值是否“等于”空

Select * from Customers where ((LastName=@LastName) or (LastName is null and @LastName is null))

2、把Null作為參數值傳遞;

對資料庫的指令中,當把空值作為參數值發送時,不能使用null(Visual Basic.NET中的Nothing)。而需要使用DBNull.Value。

事務處理

ADO.NET的事務模型已經更改

1、在AOD中,當調用StartTransaction時,調用之後的任何更新操作都被視為是事物的一部分。但是,在ADO.NET中,當調用Connection.BeginTransaction時,會傳回一個Transaction對象,需要把它與Command的Transaction屬性聯系起來。這種設計可以在一個單一連接配接上執行多個根事務。

2、如果未将Command.Transaction屬性設定為一個針對相關的Connection而啟動的Transaction,那麼Command就會失敗并引發異常。

Class TransDemo

Public void DoDemo()

SqlConnection con=new SqlConnection(“Server=localhost;Integrated Security=SSPI;database=mydatabase;”);

SqlCommand cmdUpdateScore=new SqlCommand(“UpdateScore”,con);

cmdUpdateScore.CommandType=CommandType.StoredProceduce;

cmdUpdateSocre.Parameters.Add(new SqlParameter(“@username”,”周潤發”));

cmdUpdateScore.Parameters.Add(new SqlParameter(“@score”,”700”));

SqlTransaction trans=con.BeginTransaction();

cmdUpdatScore.Transaction=trans;

try

cmdUpdateScore.ExecuteNonQuery();

trans.Commit();//no error so commit the transaction

catch

Trans.Rollback();//rollback the update

議程

1、ADO.NET架構

2、使用ADO.NET連接配接最佳練習

3、使用ADO.NET指令最佳練習

4、使用DataReader、DataSet、DataAdapter

5、使用ADO.NET的其他技巧

使用DataReader、DataSet、DataAdapter

DataSet是一種代表關系資料的記憶體駐留結構

DataTableCollection

Columns

Rows

Constraint

DataRelationCollection

ADO.NET

DataProvider

Connection<->DataAdapter對象   <-> DataSet <-> Data Use Application

         <->Command對象                   Windows Forms

           DataReader對象                   Web Forms

                                            Others

1、執行以下操作使用DataSet:

在結果的多個離散表之間進行導航。

操作來自多個資料源(例如,來自多個資料庫、一個XML檔案和一個電子表格的混合資料)的資料

在各層之間交換資料或使用XML Web服務。

重用同樣的行組,以便通過緩存獲得性能改善(例如排序、搜尋或篩選資料)。

每行執行大量處理。

2、對于下列情況,要在應用程式中使用DataReader:

不需要緩存資料。

要處理的結果集太大,記憶體中放不下。

一旦需要以隻進、隻讀方式快速通路資料。

3、DataReader的常見問題:

在通路相關Command的任何輸出參數之前,必須關閉DataReader。完成讀資料之後總是要關閉DataReader。

當通路列資料時,使用類型化通路器

一個單一連接配接每次隻能打開一個DataReader。

預設情況下,DataReader每次Read時都要把整行加載到記憶體。這允許在目前行内随即通路列。如果不需要這種随即通路,為了提高性能,就把CommandBehavior.SequentialAccess傳遞給ExecuteReader調用

如果已經完成讀取來自DataReader的資料,但仍然有大量挂起的未讀結果,就在調用DataReader的資料,但仍然有大量挂起的未讀結果,就在調用DataReader的資料,但仍然有大量挂起的未讀結果,就在調用DataReader的Close之前先調用Command的Cancel。

4、二進制大對象(BLOB)

用DataReader檢索二進制大對象(BLOB)時,應該吧CommandBehavior.SequentialAccess傳遞給ExecuteReader方法調用。

SequentialAccess将DataReader的行為設定為隻加載請求的資料。然後還可以使用GetBytes或GetChars控制每次加載多少資料。

Public void ExecuteNonQuery()

SqlConnection con=new SqlConnection(“Server=localhost;Integrated Security=SSPI;database-mydatabase;”);

SqlCommand cmdUpdateSales=new SqlCommand(“Update scoretable set score=score+200 where username=’who’”,con);

cmdUpdateSales.CommandType=CommandType.Text;

cmdUpdateSales.ExecuteNonQuery();

Public DataSet ExecuteAndFill()

SqlDataAdapter da=new SqlDataAdapter(“select username,password,score from scoretable”,con);

DataSet ds=new DataSet();

da.Fill(ds);

return ds;

其他技巧

1、避免自動增量值沖突

2、檢查開放式并發沖突

3、多線程程式設計

4、僅在需要的時候才用COM Interop通路ADO

小結

2、連接配接練習

3、指令練習