本文包括:
l .NET框架組件中包含的數據提供者信息
l DataSet 與DataReader的比較,這些對象最佳使用說明
l 說明怎樣使用DataSet、Commands和Connections
l 與XML集成的信息
l 一般的技巧
.NET框架組件中的數據提供程序是應用程序與數據源之間的一座橋梁。它允許你從數據源返回查詢的結果,在數據源上執行命令,把數據集中的改變提交到數據源。本文包含了怎樣選擇最適合需求的.NET框架組件數據提供程序。
使用哪種.NET框架組件數據提供程序
為了使應用程序獲得最佳的性能,需要使用最適合數據源的.NET框架組件數據提供程序。
連接到SQL Server 7.0及以上版本
當連接到SQL Server 7.0及以上版本時,為了獲得最佳性能應該使用SQL Server .NET 數據提供程序。SQL Server .NET數據提供程序設計為直接訪問SQL Server,沒有其它附加的技術層。下圖(圖1)說明了訪問SQL Server 7.0及以上版本的多種技術之間的差別。

圖1.訪問SQL Server 7.0及以上版本的連接方法
連接到ODBC數據源
名字空間中的ODBC .NET數據提供程序的結構與SQL Server和OLE DB的.NET數據提供程序相同。ODBC .NET數據提供程序使用"ODBC"前綴和標準的ODBC連接字符串。
注意:ODBC .NET數據提供程序包含在.NET框架組件1.1以上版本,包含ODBC .NET數據提供程序的名字空間是System.Data.Odbc。
ADO.NET提供兩個對象用于檢索關系型數據并把它存儲在內存中,分別是DataSet和DataReader。DataSet提供內存中關系數據的表現--包括表和次序、約束等表間的關系的完整數據集合。DataReader提供快速、只向前、只讀的來自數據庫的數據流。
使用DataSet時,一般使用DataAdapter(也可能是CommandBuilder)與數據源交互,用DataView對DataSet中的數據進行排序和過濾。DataSet可以被繼承來建立強化類型的DataSet,用于暴露表、行、列作為強化類型對象屬性。
下面的內容包含什么時候使用DataSet或DataReader,以及怎樣優化訪問它們所包含的數據,也包括怎樣優化DataAdapter和DataView的使用(也包括CommandBuilder)。
DataSet與DataReader的對比
在設計應用程序時,決定使用DataSet還是DataReader需要考慮應用程序需要的功能。
使用DataSet是為了實現應用程序的下述功能:
l 操作結果中的多個分離的表。
l 操作來自多個源(例如來自多個數據庫、XML文件和電子表格的混合數據)的數據。
l 在層之間交換數據或使用XML Web服務。與DataReader 不同,DataSet能被傳遞到遠程客戶端。
l 通過緩沖重復使用相同的行集合以提高性能(例如排序、搜索或過濾數據)。
l 每行執行大量的處理。在使用DataReader返回的行上進行擴展處理將使連接存在的時間比必要的更長,從而降低效率。
l 使用XML操作(例如XSLT轉換和Xpath查詢)維護數據。
在應用程序需要以下功能時使用DataReader:
l 不需要緩沖數據。
l 正在處理的結果集太大而不能全部放入內存中。
l 需要迅速一次性訪問數據,采用只向前的只讀的方式。
注意:當填充DataSet的時候,DataAdapter使用DataReader。因此使用DataAdapter代替DataSet獲得的性能是節約了DataSet消耗的內存和組裝DataSet所需要的周期。這種性能的提高大部分是有名無實的,因此你應該根據需要的功能為基礎來做設計決定。
使用強類型DataSet的好處
使用DataSet的另一個好處是它能被繼承用于建立強類型的DataSet。強類型DataSet的好處包括設計時的檢查和強類型DataSet 的Visual Studio .NET語句填充。當你為DataSet固定了大綱或關系結構時,就能建立強類型DataSet,把行和列作為對象的屬性而不是項的集合。例如,作為暴露顧客表的某一行的列名的代替,你可以暴露Customer對象的 Name屬性。強類型的DataSet衍生自DataSet類,因此不會犧牲DataSet的任何功能,也就是說,強類型的DataSet也可以是遠程的,并作為數據綁定控件(例如DataGrid)的數據源提供。如果不知道大綱,也能通過使用通常的DataSet獲得好處,但是喪失了強類型DataSet的附加特性。
在強類型DataSet中處理空值
使用強類型DataSet時,你能給DataSet 的XML大綱定義語言(XSD)作注解以確保強類型DataSet正確的處理空(Null)的引用?罩担╪ullValue)注釋使你能用String.Empty這個特定值代替DBNull、保持了空引用、或者產生一個異常。選擇其中的哪個依賴于應用程序的內容,默認情況下遇到空引用將產生一個異常。
刷新DataSet中的數據
如果你希望使用更新后的值從服務器刷新數據集中的值,使用DataAdapter.Fill。如果主鍵定義在數據表上,DataAdapter.Fill基于主鍵匹配新行,并把服務器的數據改成已存在的行。被刷新行的RowState設置為Unchanged,即使在刷新前它被修改過。注意如果給數據表定義了主鍵,DataAdapter.Fill添加新行可能重復主鍵值。
如果希望用服務器的當前值刷新一個表,并且保持表中行的改變,你必須首選使用DataAdapter.Fill組合它,填充一個新的數據表,接著將該數據表合并(Merge)進一個數據集,并把preserveChanges值設為true。
在DataSet中搜索數據
在一個數據集中查詢符合特定條件的行時,使用基于索引(index-based)的查看表將提高性能。給數據表指定主鍵(PrimaryKey)值時,就建立了一個索引。當為數據表建立數據視圖(DataView)時也建立了索引。下面是一些使用基于索引查看的技巧:
如果查詢是在數據表的主鍵列上進行的,使用DataTable.Rows.Find代替DataTable.Select。
查詢非主鍵列,可以使用數據視圖來提高多個數據查詢的速度。當給數據視圖添加排序時,將建立搜索時使用的索引。數據視圖暴露了查詢下層數據表的Find和FindRows方法。
如果你不是查詢表的排序視圖,也可以通過為數據表建立數據視圖獲得基于索引的查看表的好處。注意如果你執行數據上的多個查詢這是唯一的好處。如果你只執行單個查詢,需要建立索引的過程將因為使用索引而降低了性能。
數據視圖(DataView)結構
當數據視圖建立后,并且當Sort、RowFilter或RowStateFilter或者屬性被修改時,數據視圖為下層數據表中的數據建立索引。當建立數據視圖對象時,使用把Sort、RowFilter和RowStateFilter值作為參數的數據視圖構造函數。結果是建立了一次索引。建立"空"數據視圖,然后設置Sort、RowFilter和RowStateFilter屬性將導致至少兩次建立索引。
分頁
ADO.NET給了你從數據源返回什么數據的明顯控制,也提供了在數據集中存儲了多少數據的控制。在設計應用程序時可以考慮以下技巧:
l 避免使用DataAdapter.Fill,它使用了startRecord和maxRecords值。使用這種方式填充數據集時,數據集只填充由maxRecords參數指定的記錄個數(從參數startRecord指定的記錄開始),而不管返回的整個查詢。這導致讀取過時的"不想要的"記錄,同時使用了不必要的服務器資源來返回補充記錄。
l 用于在某個時候只返回一頁記錄的技術之一是建立一個SQL語句,該語句包含一個WHERE和ORDER BY子句,并有TOP判定。這種技術依賴于識別每個唯一行的方法。當導航到下一頁的記錄時,修改WHERE子句使它包含所有唯一標識比當前頁標識大的記錄;當導航到前面一頁時,修改WHERE子句使它包含所有唯一標識比當前頁標識小的記錄。對于兩種查詢都只返回記錄的TOP頁的記錄。當導航到前面一頁時需要對記錄進行降序排列,這將返回查詢的末尾頁(如果需要可以在顯示前對記錄進行重新排序)。
l 另一種技術是建立一個SQL語句包含TOP判定和嵌入的SELECT語句。這種技術不是基于唯一的識別每行的方法。使用這種技術的第一步是把頁面的大小與想得到的頁面數量相乘。接著把該數值傳遞給SQL查詢的TOP判定,并按升序排序。接著把這個查詢嵌入另一個查詢,該查詢從嵌入的查詢結果中選擇TOP頁面大小,按降序排列。本質上返回的是嵌入的查詢的末尾頁面。例如,為了返回頁面大小是10的查詢結果的第三頁,使用下面的命令:
|
l 如果數據不是經常改變,能通過本地維護數據集里面的記錄緩存來提高性能。例如,你能在本地數據集中存儲10頁數據,只在用戶導航超出第一頁或最后一頁時才查詢數據源檢索新的數據。
使用大綱(Schema)填充數據集
當用數據填充數據集時,DataAdapter.Fill方法使用數據集的已存在的大綱并把它與Select命令(SelectCommand)返回的數據進行組合。如果數據集中沒有與被填充的表匹配的表的名字,Fill方法將建立一張表。默認情況下,Fill只定義列和列的類型。
你能通過設置數據適配器的MissingSchemaAction屬性來重載Fill的默認的行為。例如,要使Fill建立的表包含主鍵信息、唯一約束、列屬性、是否允許空值、列的最大長度、只讀列、自動增加列等等,只需要指定DataAdapter.MissingSchemaAction為MissingSchemaAction.AddWithKey。作為選擇,你能在調用DataAdapter.Fill前調用DataAdapter.FillSchema來確保數據集被填充時大綱已經準備好了。
調用FillSchema將再次訪問服務器并檢索附加的大綱信息。為了提高性能,最好指定數據集的大綱,或者在調用Fill前設置數據適配器的MissingSchemaAction。
使用命令構造器(CommandBuilder)的經驗
命令構造器根據數據適配器的SelectCommand屬性自動生成數據適配器的InsertCommand、UpdateCommand和DeleteCommand屬性(假若SelectCommand執行單個表上的選擇(SELECT))。
l 命令構造器的使用應該限制在設計時或者ad-hoc情況下。需要的生成數據適配器命令屬性的過程妨礙了性能。如果你預先知道INSERT/UPDATE/DELETE語句的內容,應該顯式地設置它們。好的設計技巧是為INSERT/UPDATE/DELETE命令建立存儲過程并明確地配置數據適配器命令屬性來使用它們。
l 命令構造器使用數據適配器的SelectCommand屬性來決定其它命令屬性的值。如果數據適配器的SelectCommand自身改變了,一定要調用RefreshSchema來更新命令屬性。
l 如果命令屬性是空的(默認情況下命令屬性是空的),命令構造器只為數據適配器命令屬性生成一個命令。如果你明確地設置一個命令屬性,命令構造器不會覆蓋它。如果你希望命令構造器為一個已經設置了的命令屬性生成一個命令,要把命令屬性設置為空。
批處理SQL語句
很多數據庫支持在一個命令執行中組合、批處理多個命令執行。例如,SQL Server允許你使用分號分隔命令。把多個命令組合成為一個減少了對服務器的訪問次數,可以提高應用程序的性能。例如,你能在本地應用程序中存儲所有的刪除,并在數據源發布一個批處理命令調用來刪除它們。
盡管它提高了性能,但是也增加了應用程序管理數據集里面數據更新的復雜性。為了保持簡單性,你也許會為數據集中的每個數據表建立一個數據適配器。
使用多個表填充數據集
如果使用批處理SQL語句檢索多個表并填充一個數據集,第一張表的名字使用Fill方法指定的表名,后面的表的名字是Fill方法指定的名字加上一個數字,從1開始逐漸增加。例如,如果運行下面的代碼:
|
從Customers表中得到的數據放在叫"Customers"的數據表中,從Orders表中得到的數據放在"Customers1"數據表中。
你可以在數據表被填充后修改"Customers1"表的屬性為"Orders"。但是接下來的填充的結果是"Customers"表被重新填充,但是"Orders"表被略過了并且建立了另一個"Customers1"表。為了避免這種情況,建立一個把"Customers1"映射到"Orders"的DataTableMapping,并且為其它的表建立映射。例如:
|
使用DataReader
下面是使用DataReader提高性能的一些技巧:
l 在訪問任何與命令(Command)相關的輸出參數前DataReader必須關閉。
l 在讀完數據后就關閉DataReader。如果你正在使用的連接只返回該DataReader,在關閉DataReader后立即關閉連接。
l 另一種明確地關閉連接的方法是給ExecuteReader方法傳遞CommandBehavior.CloseConnection以確保當DataReader關閉時相關的連接關閉了。如果你從某個方法返回DataReader,并且沒有辦法控制DataReader或者相關的連接關閉的情況下特別有用。
l DataReader不能在層之間遠程訪問。DataReader是設計用于連接數據訪問的。
l 使用類型化的存取程序(例如GetString、GetInt32等等)來訪問列數據。這節省了將GetValue返回的對象作為特定類型的必要的處理。
l 在某一時刻只有一個DataReader能夠打開。。在ADO中,如果你打開一個連接并請求兩個使用只向前的只讀游標的記錄集,ADO隱性地為游標的生命周期的數據存儲打開第二個不在連接池中的連接,接著隱性地關閉它。在ADO.NET中,如果你想在同一個數據存儲上同時打開兩個DataReader,你必須明確地建立兩個連接,每個DataReader一個。通過這種方法ADO.NET給了你對連接池使用的更多控制。
l 默認情況下,DataReader在每個Read方法中把整個行載入內存中。這允許你隨機訪問當前行的任意列。如果隨機訪問是不必要的,為了提高性能,把CommandBehavior.SequentialAccess傳遞給ExecuteReader調用。這改變了DataReader的默認行為,只在需要時才把數據載入內存。注意CommandBehavior.SequentialAccess要求你按次序訪問返回的列。也就是,一旦你讀過了返回的某個列,就不能再次讀取它的值了。
l 如果你結束了從DataReader中讀取數據,但是仍然有大量的未讀取的結果等待,那么調用Command的Cancel比調用DataReader 的Close好。調用DataReader 的Close引起它檢索等待的結果并且先清空流后關閉游標。調用Command的 Cancel刪除服務器上的結果,因此當DataReader關閉時,它不需要再讀取結果。如果你從Command返回輸出參數,則調用Cancel刪除它們。如果你要讀取任何輸出參數,不要調用Command 的Cancel;最后調用DataReader的 Close。
二進制大對象(BLOB)
當使用DataReader檢索二進制大對象時,必須給ExecuteReader方法調用傳遞CommandBehavior.SequentialAccess。因為DataReader的默認行為是在每個Read中把整行載入內存中,但是由于BLOB可能很大,結果可能是一個BLOB對象使用大量的內存。SequentialAccess把DataReader的行為設置為只載入必要的數據,接著你能使用GetBytes或者GetChars控制每次載入多少數據。
記住使用SequentialAccess時,你不能無序地訪問DataReader返回的不同字段。也就是說,如果查詢返回三個列,第三個是BLOB,并且你希望訪問前兩個列的數據,你必須先訪問第一個列,接著在訪問BLOB數據前訪問第二個列。這是因為現在數據是按次序返回的,在DataReader讀過它后不能再次訪問。
使用命令(Command)
ADO.NET為命令執行提供了幾個不同的方法,同時也為優化命令的執行提供了不同的選擇。下面的技巧包括怎樣選擇最好的命令執行和怎樣提供一個被執行命令的性能。
使用OleDbCommand的最好經驗
不同的.NET框架組件數據提供程序之間的命令執行是盡可能標準的。但是,在這些數據提供程序間也有些不同。下面的一些可以調整OLE DB數據提供程序命令執行的技巧:
l 與ODBC CALL語法一起使用CommandType.Text來調用存儲過程。僅僅使用CommandType.StoredProcedure生成ODBC CALL語法。
l 一定要設置OleDbParameter類型、大。ㄈ绻捎茫、精度和小數位(如果參數是數值型或者十進制型)。注意如果你沒有明確地提供參數信息,OleDbCommand使用每一個命令執行重新建立OLE DB參數存取程序。
使用SqlCommand的經驗
使用SqlCommand執行存儲過程的技巧:如果你要調用一個存儲過程,為SqlCommand的 CommandType屬性指定StoredProcedure的CommandType。這樣就刪除了在命令執行前分析命令的需求,明確地把它標識為存儲過程了。
Prepare方法的使用
Command.Prepare方法能夠提高數據源中重復的參數化命令的性能。Prepare指示數據源為多個調用優化特定的命令。為了更高效率地使用Prepare,你必須十分清楚數據源怎樣回應Prepare調用。對于類似SQL Server 2000的數據源,命令是隱式優化的,對Prepare的調用是沒有必要的,但是對于另一些數據源,例如SQL Server 7.0,Prepare效率更高。
明確地指定大綱和元數據
在ADO.NET中當用戶沒有指定元數據信息時,有很多對象推導這些信息。例如:
l DataAdapter.Fill方法,如果不存在的話,它在記錄集中建立表和列。
l CommandBuilder,它為單個的SELECT語句生成數據適配器命令屬性。
l CommandBuilder.DeriveParameters,它組合Command對象的Parameters集合。
但是每次使用這些特性時都會造成效率降低。我們推薦主要在設計時和ad-hoc應用程序中使用這些特性。在可能的情況下,明確地指定大綱和元數據,包括在數據集中定義表和列,定義數據適配器的Command屬性,定義Command的Parameter信息。
ExecuteScalar和ExecuteNonQuery
如果你希望返回單個值,例如Count(*)、 Sum(Price)、或者Avg(Quantity),你可以使用Command.ExecuteScalar。ExecuteScalar返回第一行第一列的值,返回結果集是數量值。ExecuteScalar通過一步完成不僅簡化了代碼而且提高了性能,而這些工作在使用DataReader時將需要兩個處理步驟。
當使用不返回行的SQL語句時,類似修改數據(例如插入、更新或者刪除)或者只返回輸出參數或值,使用ExecuteNonQuery。它通過建立一個空DataReader刪除了任何必要的處理。
空值的檢測
如果數據庫的某張表的一個列允許空值,你不能使用某個與空值相等的參數來測試它。作為代替,需要編寫一個WHERE子句來檢測是否列和參數都是空值。下面的SQL語句返回LastName列與賦予@LastName的值相同的行,或者LastName 列和@LastName參數都為空的行:
|
把空(Null)作為參數值傳遞
當在命令中把空值作為參數值發送給數據庫時,不能使用null(Visual Basic .NET中的Nothing)。作為代替必須使用DBNull.Value。例如:
|
執行事務
事務模塊為ADO.NET作了一些改變。在ADO中,當調用StartTransaction時,該調用后面的任何更新都被認為是該事務的一部分。但是在ADO.NET中,當調用Connection.BeginTransaction時,返回的Transaction對象必須與Command的Transaction屬性關聯。這種設計使你能在一個連接上執行多重事務。如果Command.Transaction屬性沒有設置為開始就與連接關聯的Transaction,Command失敗并出現異常。
使用連接
高性能的應用程序保持使用最少次數的數據源的連接,也利用了類似連接池的性能增強技術。下面的技巧幫你使用ADO.NET連接數據源時獲得更好的性能。
連接池
SQL Server、OLE DB和.NET框架組件數據提供程序隱性為ODBC提供了連接池。你可以在連接字符串中指定不同的屬性控制連接池的行為。
用DataAdapter優化連接
數據適配器的Fill和Update方法自動地為相關的命令屬性打開特定的連接(如果它被關閉的話)。如果Fill或Update方法打開了連接,Fill或Update將在操作完成時關閉它。為了提高性能,只在必要時保持數據庫連接打開,同時為多個操作減少打開和關閉連接的次數。
我們推薦如果你只執行單個的Fill或Update方法調用,你應該允許Fill或Update隱式打開和關閉連接。如果大量調用Fill或者Update,我們推薦顯式打開,進行Fill或Update調用,然后顯式關閉連接。
此外執行事務時,在開始事務前明確地打開連接,在完成事務后明確地關閉連接。例如:
|
經常關閉連接(Connection)和DataReader
當停止使用Connection或者DataReader對象時,明確地關閉它們。盡管無用單元收集程序最終會清除這些對象,并釋放連接和其它可管理資源,但是無用單元收集只在必要時才發生。因此確保昂貴的資源明確地被釋放仍然是你的職責。此外,連接如果沒有被明確的釋放將使它不會返回連接池。例如,如果連接池到達了最大值并且一個連接還有效,該超出范圍并且沒有被明確關閉的連接才返回到連接池。
注意不要在類的Finalize方法中調用Connection、DataReader、或者其它可管理對象的Close或者Dispose方法。在該方法中只釋放類直接擁有的不可管理資源。如果類中沒有任何不可管理資源,在類定義中不要包含Finalize方法。
在C#中使用"Using"語句
對C#程序員來說,確保經常關閉Connection和DataReader對象的一個簡便方法是使用using語句。Using語句會自動調用留在Using語句范圍內的被使用的對象上的Dispose,如下所示:
|
避免訪問OleDbConnection.State屬性
如果連接打開了,OleDbConnection.State使本地OLE DB向DATASOURCEINFO屬性集調用IDBProperties.GetProperties來獲取DBPROP_CONNECTIONSTATUS屬性,這可能引起重新返回數據源。換句話說,檢查State屬性可能花費很大。因此只在必要時才檢查State屬性。如果你需要經常檢查該屬性,你監聽OleDbConnection的StateChange事件會使應用程序的性能更好。
與XML集成
ADO.NET在數據集中提供了廣泛的XML集成,并且暴露了一些SQL Server 2000及以上版本所提供的XML功能。你能使用SQLXML 3.0來訪問SQL Server 2000及以上版本所提供的XML功能。下面是使用XML和ADO.NET的一些技巧和信息。
數據集與XML
數據集與XML緊密結合,提供了執行下面操作的能力:
l 從XSD大綱載入數據集的大綱或者關系結構。
l 從XML載入數據集的內容。
l 當沒有提供大綱時根據XML文檔的內容推斷數據集的大綱。
l 將數據集的大綱寫成XSD大綱。
l 將數據集的內容寫成XML。
l 使用數據集同步訪問數據的相關表現、使用XmlDataDocument訪問數據的層次表現。
注意:你能使用這種同步在數據集的數據上應用XML功能(例如Xpath查詢和XSLT變換),或提供所有的關系型視圖,或者在保持原XML不變的情況下提供XML文檔中的數據的子集。
大綱接口
當從XML文件中載入數據集時,你能從XSD大綱中載入數據集的大綱,或者在載入數據前預先定義表和列。如果沒有XSD大綱,并且你也不知道為XML文件的內容定義怎樣的表和列,你能根據XML文檔的結構推斷大綱。
大綱推理作為遷移工具是有用的,但是由于推理過程有下面的限制,它只限于應用程序設計時使用:
l 推理大綱引入了附加的處理將降低應用程序的性能。
l 所有推理列的類型都是字符串型。
l 推理過程是不確定的。這就是說,它基于XML文件而不是預定的大綱。結果是你可能有兩個XML文件,它們有相同的預定大綱,卻因為它們的內容不同形成了兩個完全不同的推理大綱。
為XML查詢服務的SQL Server
如果你為XML查詢返回SQL Server 2000結果,你能使用.NET框架組件SQL Server數據提供程序直接用SqlCommand.ExecuteXmlReader方法建立一個XmlReader。
SQLXML可管理類
在.NET框架組件中有一些類暴露了XML為SQL Server 2000提供的功能。這些類都在Microsoft.Data.SqlXml名字空間中,添加了執行Xpath查詢和XML模板文件的能力,也能把XSLT轉換為數據。
避免自動增加(Auto-Increment)值沖突
和許多數據源一樣,DataSet允許你在添加新行時識別自動增加值的列。在DataSet中使用自動增加列時,由于數據源也有自動增加列,需要避免添加到DataSet中的本地行號與添加到數據源中的行之間的沖突。
例如,假設一個表的自動增加主鍵列是CustomerID。兩個新客戶信息添加到該表,獲得的自動增加CustomerID值分別是1和2。接著只有第二個客戶行給數據適配器傳遞的Update方法,在數據源中新添加的行接受的自動增加CustomerID值是1,與數據集中的2不匹配。當數據適配器用返回值填充表中的第二行時,由于第一個顧客行的CustomerID是1,便出現了錯誤。
為了避免這種情況,我們推薦當使用數據源和數據集中有自動增加列時,數據集中的該列的AutoIncrementStep設為-1,AutoIncrementSeed設為0,同時確保數據源中生成的自動增加標識值從1開始,步長為正。結果是數據集生成負的自動增加值,不會與數據源產生的正自動增加值沖突。另一種選擇是使用Guid類型的列帶有自動增加列,該算法產生的Guid值在數據集和數據源中永遠不同。
如果你的自動增加列永遠簡單的作為唯一值,沒有其它的意義,考慮使用Guid代替自動增加列。它們是唯一的,避免了做另外的工作處理自動增加列。
查找優化的并發性故障
因為DataSet被設計為從數據源斷開,所有必須確保當多個客戶端更新數據源的數據時應用程序避免沖突。
測試優化并發性錯誤有多種技術。一種是在表的列中包含時間戳。另一種技術是通過使用SQL語句中的WHERE條件檢測來驗證行中所有的源列值與數據庫中的匹配。
多線程編程
ADO.NET的優化是為了提高性能、吞吐量和可伸縮性。結果是ADO.NET不鎖定資源并且只能在單個線程中使用,其中一個例外是DataSet,它對多個閱讀程序來說是線程安全安的。但是在寫的時候必須鎖定DataSet。
只在必要的時候使用COM交互操作(Interop)訪問ADO
ADO.NET被設計成大量應用程序的最佳解決方案。但是,有些應用程序需要只能使用ADO對象。在這些情況下,應用程序能使用COM交互操作訪問ADO。注意使用COM交互操作訪問ADO的數據將極大的降低性能。設計應用程序時,在實現使用COM交互操作訪問ADO這種設計前首選決定ADO.NET是否符合設計需要。
相關文章
ADO.NET中的視圖和過濾器 |
用ADO.Net實現通用數據庫編程 |
直接用ADO操作Access數據庫源碼 |
延伸閱讀
文章來源于領測軟件測試網 http://www.kjueaiud.com/