国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 編程 > .NET > 正文

.NET 數據訪問架構指南(一)

2024-07-10 12:59:44
字體:
來源:轉載
供稿:網友
概述:本文提供了在多層.net應用程序中實施基于ado.net的數據訪問層的指導原則。其重點是一組通用數據訪問任務和方案,并指導你選擇最合適的途徑和技術(68張打印頁)。

目錄

ado.net簡介
管理數據庫鏈接
錯誤處理
性能
通過防火墻建立鏈接
處理 blobs
事務處理
數據分頁
簡介

如果你在為.net應用程序設計數據訪問層,那么就應該把 microsoft ado.net用作數據訪問模型。ado.net擴展豐富,并且支持結合松散的數據訪問需求、多層web應用程序及web服務。通常,它利用許多擴展豐富的對象模型, ado.net提供了多種方法用于解決一個特定問題。

本文將指導你選擇最合適的數據訪問方法,其做法是詳細列出大范圍的通用數據訪問方案,提供運用技巧,并且建議最優實踐。本文還回答了其它經常問到的問題:何處最適合存放數據庫鏈接字符串?應如何實現鏈接存儲池?如何處理事務?如何實現分頁以允許用戶在許多記錄中滾動?

注意本文的重點是ado.net的使用:利用sql server .netdata provider--隨ado.net一起提供的兩個供應器之一--訪問microsoft sql server 2000。本文在合適的地方,將突出顯示在你使用ole db .net數據供應器訪問其它ole db敏感數據源時需要注意的所有差別。

對于利用本文所討論的指導原則和最優實踐所開發的數據訪問組件的具體實現,見(data access application block)數據訪問應用程序塊。注意,本實現的源代碼是可以獲得的,并且能直接用于你的.net應用程序中。

誰應當閱讀本文?

本文為希望構建.net應用程序的應用程序設計師和企業開發人員提供了指導原則。如果你負責設計并開發多層.net應用程序的數據層,那么請閱讀本文。

你首先需要知道什么?

要利用本指南構建.net應用程序,你必須有利用activex數據對象(ado)和/或 ole db開發數據訪問代碼的實際經驗,及sql server經驗。你也必須明白如何為.net平臺開發管理代碼,并且也必須清楚ado.net數據訪問模型引入的基本變化。有關.net開發的更多信息,見http://msdn.microsoft.com/net 。

ado.net簡介

ado.net是.net應用程序的數據訪問模型。它能用于訪問關系型數據庫系統,如sql server 2000,及很多其它已經配備了ole db供應器的數據源。在某種程度上,ado.net代表了最新版本的ado技術。然而,ado.net引入了一些重大變化和革新,它們專門用于結構松散的、本質非鏈接的web應用程序。關于ado 與 ado.net的比較,見msdn中的“用于ado程序員的ado.net”一文。

ado.net引入的一個重要變化是,用datatable, dataset, dataadapter, 和 datareader對象的組合代替了ado recordset對象。datatable表示來自一個表的行集合,在這方面它與recordset類似。dataset表示datatable對象的集合,及與其它表綁定在一起的關系和限制。實際上,dataset是具有內置的擴展標記語言(xml)支持的內存中的關聯結構。

dataset的一個主要特點是,它對底層的數據源一無所知,而這些數據源可能用于對其進行填充。這是一個分離的用于表示數據集合的獨立實體,并且它可通過多層應用程序的不同層由一個組件傳遞到另一組件。它也可作為xml 數據流被序列化,因而非常適合于不同類型平臺間的數據傳輸。ado.net使用dataadapter對象為發送到和來自dataset及底層數據源的數據建立通道。dataadapter對象還支持增強的批更新特性,以前這是recorder的相關功能。

圖1顯示了完整的dataset對象模型。


圖1 dataset 對象模型

.net 數據供應器

ado.net 依靠.net 數據供應器的服務。 它們提供了對底層數據源的訪問,包括四個主要對象(connection, command, datareader,及dataadapter),目前,ado.net只發行了兩個供應器:

sql server .net 數據供應器。這是用于microsoft sql server 7.0及其以后版本數據庫的供應器,它優化了對sql server的訪問,并利用 sql server內置的數據轉換協議直接與sql server通信。
當鏈接到sql server 7.0 或 sql server 2000時,總是要使用此供應器。
ole db .net 數據供應器。. 這是一個用于管理ole db 數據源的供應器。它的效率稍低于sql server .net data provider,因為在與數據庫通信時,它需通過ole db層進行呼叫。注意,此供應器不支持用于開放數據庫鏈接(odbc),msdasql的ole db供應器。對于odbc數據源,應使用odbc .net數據供應器。有關與ado.net兼容的ole db供應器列表,見。
目前測試版中的其它.net數據供應器包括:

odbc .net 數據供應器。目前beta 1.0版可供下載。它提供了對odbc驅動器的內置訪問,其方式與ole db .net數據供應器提供的對本地ole db供應器的訪問方式相同。關于odbc .net及beta版下載的更多信息見.
用于從sql server 2000中得到xml的管理供應器。用于sql server web升級2版的xml還包括了專用于從sql server 2000中得到xml的管理供應器。關于此升級版本的更多信息,見 .
名稱空間組織

與每個.net數據供應器相關的類型(類,結構,枚舉,等等)位于它們各自的名稱空間中:

system.data.sqlclient. 包含了 sql server .net 數據供應器類型。
system.data.oledb. 包含了 ole db .net數據供應器類型。
system.data.odbc. 包含了odbc .net數據供應器類型。
system.data. 包含了獨立于供應器的類型,如dataset及datatable。
在各自關聯的名稱空間中,每個供應器都提供了connection, command, datareader, 及 dataadapter對象的實現。sqlclient實現都有前綴"sql";而oledb實現前面都有前綴"oledb"。例如,connection對象的 sqlclient實現是sqlconnection。而oledb實現是oledbconnection。類似的,dataadapter對象的兩種實現是sqldataadapter 和oledbdataadapter。

通用編程

如果你很有可能以不同的數據源為目標,并希望將代碼從一種數據源移植到另一數據源,那么可以考慮對system.data名稱空間中的idbconnection, idbcommand, idatareader,和idbdataadapter接口進行編程。connection, command, datareader, 及 dataadapter對象的所有實現都必須支持這些接口。

關于實現.net數據供應器的更多信息,見http://msdn.microsoft.com/library/en-us/cpguide/html/cpconimplementingnetdataprovider.asp.

圖2顯示了數據訪問堆棧及ado.net如何與其它數據訪問技術,包括ado和ole db,聯系起來。該圖還顯示了ado.net模型中的兩個管理供應器和主要對象。


圖2 數據訪問堆棧

關于ado到ado.net的演化,見msdn雜志2000年11月期的文章“ado+簡介:用于微軟.net框架的數據訪問服務”。

存儲過程與直接sql的比較

在本文剩余部分的大部分代碼片段中,都使用了sqlcommand對象調用存儲過程去執行數據庫操作。在一些例子中,你見不到sqlcommand對象,因為存儲過程名直接傳遞給了sqldataadapter對象,但這仍將導致sqlcommand對象的創建。

使用存儲過程而非sql語句的原因是:

存儲過程通常會使性能增加,因為數據庫可以優化過程使用的數據訪問計劃,并對其進行緩存以備將來重用。
在數據庫中,存儲過程可分別得到保護。客戶可以被給予執行某個存儲過程的權限,但無權處理底層的表。
存儲過程將導致維護簡單,因為在一個已部署組件內,修改存儲過程通常要比修改硬編碼的sql語句簡單。
存儲過程增加了一個從底層的數據庫結構中提取出的層。存儲過程的客戶與存儲過程的實現細節及底層結構被隔離開了。
存儲過程可以降低網絡流量,因為sql語句可以以批處理的方式執行,而不是從客戶端發送多個請求。
屬性與構造函數的比較

可以通過構造函數參數或直接設置屬性來為ado.net對象設置具體的屬性值。例如,下面的代碼片段在功能上是等同的。

// use constructor arguments to configure command object
sqlcommand cmd = new sqlcommand( "select * from products", conn );

// the above line is functionally equivalent to the following
// three lines which set properties explicitly
sqlcommand cmd = new sqlcommand();
cmd.connection = conn;
cmd.commandtext = "select * from products";

從性能角度來說,兩種方法的差別可以忽略,因為設置或獲得.net對象的屬性比對com對象執行類似操作要有效得多。

所作出的選擇只是個人愛好和編碼風格而已。然而,明確地設置屬性的確使代碼易于理解(特別是當你不熟悉ado.net對象模型時),便于調試。

注意 過去,vb開發人員被建議避免使用"dim x as new…"結構創建對象。在com環境中,這些代碼將導致com對象創建過程的“短路”,產生一些奇妙的和不怎么奇妙的錯誤。然而,在.net環境中,這已不再是一個問題。

管理數據庫鏈接

數據庫鏈接是一種危險的、昂貴的、有限的資源,特別是在多層web應用程序中。你必須正確管理你的鏈接,因為你的方法將極大的影響應用程序的整體升級性。還有,必須仔細考慮在哪兒存放鏈接字符串。你需要一個可配置的、安全的位置。

在管理數據庫鏈接和鏈接字符串時,你應當努力:

通過跨多個客戶多路復用一池數據庫鏈接來幫助實現應用程序的擴展性。
采用可配置的、高性能的鏈接池戰略。
在訪問sql server時使用微軟windows操作系統認證。
避免中間層的冒充。
安全地存儲鏈接字符串。
較晚地打開數據庫鏈接,而較早地關閉它們。
本節討論鏈接池,并幫你選擇合適的鏈接池戰略。其它可選方法也是存在的。本節也將考慮如何管理、存儲、控制數據庫鏈接字符串。最后,本節還提供了兩個編碼方案,使用它們將有助于確保鏈接已可靠關閉,并返回到鏈接池中。

鏈接池

數據庫鏈接池使應用程序能夠重用池中的現有鏈接,而不是重復地建立對數據庫的鏈接。這種技術將極大地增加應用程序的可擴展性,因為有限的數據庫鏈接可以為很多的客戶提供服務。此技術也將提高性能,因為能夠避免用于建立新鏈接的巨大時間。

數據訪問技術,如odbc和ole db,提供了多種形式的鏈接池,它們可配置到不同級別上。這兩種方式對數據庫客戶端應用程序來說都是透明的。ole db鏈接池經常被稱為會話或資源池。

關于微軟數據訪問組件(mdac)中池的一般討論,見http://msdn.microsoft.com/library/en-us/dnmdac/html/pooling2.asp。

ado.net數據供應器提供了透明的鏈接池,每種鏈接池的確切機制對每種供應器來說是不同的。本節討論的鏈接池是關于:

sql server .net數據供應器
ole db .net數據供應器
用sql server .net 數據供應器池化

如果正在使用sql server .net數據供應器,那么就可使用該供應器提供的鏈接池化支持特性。它是由供應器在管理代碼內內置實現的對事務敏感的高效機制。每個過程都將創建池,并且直到過程結束,池才被取消。

你可以透明地使用此種鏈接池,但應當清楚池是如何被管理的,并要知道可以用哪些選項來調整鏈接池。

如何配置sql server .net數據供應器鏈接池

可以使用一組名稱-值對以鏈接字符串的形式配置鏈接池。例如,可以配置池是否有效(默認是有效的),池的最大、最小容量,用于打開鏈接的排隊請示被阻斷的時間。下面的示例字符串配置了池的最大和最小容量。

"server=(local); integrated security=sspi; database=northwind;
max pool size=75; min pool size=5"

當鏈接打開,池被創建時,多個鏈接增加到池中以使鏈接數滿足所配置的最小值。此后,鏈接就能增加到池中,直到配置的最大池計數。當達到最大計數時,打開新鏈接的請求將排隊一段可配置的時間。

選擇池容量

能建立最大極限對于管理幾千用戶同時發出請求的大型系統來說是非常重要的。你需要監視鏈接池及應用程序的性能,以確定系統的最優池容量。最優容量還要依賴于運行sql server的硬件。

在開發期間,也許需要減小默認的最大池容量(目前是100)以幫助查找鏈接泄漏。

如果設立了最小池容量,那么當池最初被填充以達到該值時,會導致一些性能損失,盡管最初鏈接的幾個客戶會從中受益。注意,創建新鏈接的過程被序列化了,這就意味著當池最初被填充時,服務器無法處理同時發生的請求。

關于監視鏈接池的更多信息,見本文監視鏈接池一節。關于鏈接池鏈接字符串關鍵字的完整列表,見http://msdn.microsoft.com/library/en-us/cpguide/html/cpconconnectionpoolingforsqlservernetdataprovider.asp。

更多信息

在使用sql server .net數據供應器鏈接池時,必須清楚:

鏈接是通過對鏈接字符串精確匹配的法則被池化的。池化機制對名稱-值對間的空格敏感。例如,下面的兩個鏈接字符串將生成單獨的池,因為第二個字符串包含了一個額外的空字符。
sqlconnection conn = new sqlconnection(
"integrated security=sspi;database=northwind");
conn.open(); // pool a is created

sqlconmection conn = new sqlconnection(
"integrated security=sspi ; database=northwind");
conn.open(); // pool b is created (extra spaces in string)

在.net框架beta版中,當在調試器中運行時,鏈接池化總是失效了。在調試器外,對調試版和發行版,鏈接池都能正常運作。.net框架的最終發行版(rtm)取消了這種限制,鏈接池在所有情況下都能運行。
鏈接池被劃分為了多個特定于事務的池和一個用于目前沒有列在事務中的多個鏈接的池。對于與特定事務上下文相關的線程,將從(包含了與事務建立的鏈接的)合適的池中返回鏈接。這使得使用已建立的鏈接成為透明過程。
用ole db .net數據供應器池化

ole db .net數據供應器利用ole db資源池化的底層服務將鏈接存儲到池中。很多方法可用于配置資源池化:

可以使用鏈接字符串來配置、使能資源池化或使其使失效。
可以使用注冊表。
可以通過程序來配置資源池化。
為了避開與注冊表相關的部署問題,應避免使用注冊表配置ole db資源池化。

關于ole db 資源池化的更多細節,見msdn中“ole db程序員參考”一書的第19章:ole db服務中的資源池化部分。

用池化對象管理鏈接池化

作為windows dna開發人員,建議你使ole db資源池化和/或odbc鏈接池化失效,并把com+對象池化用作將數據庫鏈接存儲到池中的技術。這樣做主要出于兩個原因:

池容量和極限可以(在com+目錄)被明確配置。
性能提高了。池化對象的方法可以成倍的勝過固有池化。
然而,由于sql server .net數據供應器內置地使用池化,所以(在使用此供應器時)你不再需要開發自己的對象池化機制。這樣就可以避免手工事務征募帶來的復雜性。

如果正在使用ole db .net數據供應器,那么考慮com+對象池化以從高級配置和改進的性能中受益。如果你為此目的開發一個池化對象,那么必須使用ole db資源池化和自動事務征募失效(例如,通過將“ole db services=-4”包含進鏈接字符串中)。必須在池化對象的實現中處理事務征募。

監視鏈接池化

要監視應用程序對鏈接池化的應用情況,可以使用隨sql server發行的profiler工具,或隨微軟windows 2000發行的性能監視器。

要利用sql server profiler 監視鏈接池化,操作如下:

單擊開始,指向程序,指向microsoft sql server,然后單擊profiler運行profiler。
在文件菜單中,指向新建,然后單擊跟蹤。
提供鏈接內容,然后單擊確定。
在跟蹤屬性對話框中,單擊事件標簽。
在已選事件類別列表中,確保審核登錄和審核登出事件顯示在安全審核下面。
單擊運行開始跟蹤。在鏈接建立時,將會看到審核登錄事件;在鏈接關閉時看到審核登出事件。
要通過性能監視器監視鏈接池化,操作如下:

單擊開始,指向程序,指向管理工具,然后單擊性能運行性能監視器。
在圖表背景中右擊,然后單擊增加計數器。
在性能對象下拉列表框中,單擊sql server:通用統計。
在出現的列表中,單擊用戶鏈接。
單擊增加,然后單擊關閉。
注意 .net框架的rtm版本將另外包含一組ado .net性能計數器(這些計數器能與性能監視器結合起來使用),這些計數器用于為sql server .net數據供應器監視并積累鏈接池化狀態。

管理安全性

盡管數據庫鏈接池化提高了應用程序的整體擴展性,這也意味著你不再能夠在數據庫端管理安全性。這是因為為了支持鏈接池化,鏈接字符串必須是相同的。如果需要跟蹤每個用戶的數據庫操作,那么考慮為每個操作增加一個參數,通過這個參數就可以傳遞用戶身份,手工將用戶活動記入數據庫。

使用windows 認證

在鏈接到sql server時,應當使用windows認證,因為它提供了許多優點:

安全性易于管理,因為使用了單一(windows)安全模型而不是分散的sql server安全模型。
避免了在鏈接字符串中嵌入用戶名和密碼。
用戶名和密碼不是以明文方式在網絡中傳輸的。
通過密碼過期期限,最小長度,多次無效登錄請求后帳號鎖定提高了登錄的安全性。
性能

.netbeta 2版的性能測試表明,使用windows認證與使用sql server認證相比,要花費更多的時間才能打開池化的數據庫鏈接。然而,盡管windows認證的成本較高,但與執行一個命令或存儲過程所花費的時間相比,其(引起的)性能損失相對來說并不重要。結果,上面所列出的windows認證的優點通常會稍微超過性能損失。

同樣,當打開一個池化鏈接時,在.net框架的rtm版本中,windows認證與sql server認證的差別有望變得更不明顯。

避免在中間層中冒充

windows認證需要訪問數據庫的windows帳號。雖然看上去在中間層中使用冒充更符合邏輯,但必須避免這樣做,因為損害鏈接池化并對應用程序的擴展性產生嚴重影響。

為了解決這個問題,考慮對有限的windows帳號(而不是被認證的負責人)實施冒充,每個帳號代表一個特定的角色。

例如,可以考慮下面的方法:

創建兩個windows帳號,一個用于讀操作,一個用于寫操作(也可以用單獨的帳號映射針對特定應用程序的角色。例如,可以為互聯網用戶使用一個帳號,而為內部操作員和/或管理員使用另外的帳號)。
將每個帳號映射到一個sql server數據庫角色,然后為每個角色設置所需的數據庫權限。
在數據訪問層中使用應用程序邏輯確定執行數據庫操作時,哪個windows帳號需要冒充。
注意 每個帳號必須是同一域或信任域中在internet信息服務(iis)和sql server中存在的域帳號;也可以是在每臺計算機上創建(具有相同用戶名和密碼)的匹配帳號。

為網絡庫使用tcp/ip

sql server 7.0及其以后版本支持用于所有網絡庫的windows認證。使用tcp/ip可以獲得配置、性能及擴展性優點。關于使用tcp/ip的更多信息,見本文通過防火墻建立鏈接 一節。

存儲鏈接字符串

有多種方法可存儲鏈接字符串,每種方法具有不同程度的靈活性和安全性。盡管在源代碼中對字符串進行硬編碼提供了最優性能,但文件系統緩存確保了與在文憑系統外部存儲字符串相關的性能損失可被忽略。實際上外部鏈接字符串(允許管理員進行配置)所提供的附加靈活性在任何情況下都是受歡迎的。

選擇存儲鏈接字符串的方法時,首先要考慮的兩個重要因素是配置的安全性與簡易性,其次是性能。

可以選擇將數據庫鏈接字符串存儲在下列位置:

應用程序配置文件 例如用于asp.net web應用程序的web.config文件。
通用數據鏈接文件(udl) (只被ole db .net 數據供應器所支持)
windows 注冊表
定制文件
com+ 目錄,通過過使用構造字符串(只用于服務組件)
使用windows認證訪問sql server,就可以避免在鏈接字符串存儲用戶名和密碼。如果 安全需求要求更嚴格的方式,那么就考慮以加密格式存儲鏈接字符串。

對于asp.net web應用程序,以加密格式將鏈接字符串存儲在web.config文件中是一種安全而可配置的解決方案。

注意,在鏈接字符串中將persist security info命名值設置為假,就可以阻止利用sqlconnection 或oledbconnection對象的connectionstring屬性返回對安全敏感的內容,如密碼。

下面幾個小節討論了如何用這些方法存儲鏈接字符串,并說明了相對的優點和缺點。這使你能根據特定的應用程序環境作出相應的的選擇。

使用xml應用程序配置文件

可以使用元素appsettings將數據庫鏈接字符串存儲在應用程序配置文件的定制設置部分。該元素支持任意關鍵字-值對,如下面的代碼片段所示:

<configuration>
<appsettings>
<add key="dbconnstr"
value="server=(local);integrated security=sspi;database=northwind"/>
</appsettings>
</configuration>

注意:appsettings元素現在在configuration元素下面,并且不能直接出現在system.web下面。

優點

易于部署。通過常規.net xcopy部署,鏈接字符串隨配置文件一起被部署。
通過程序易于訪問。configurationsettings類的appsettings屬性使得在運行時讀取數據庫鏈接字符串更為簡單。
支持動態更新(僅限于asp.net)。如果管理員更新了web.config文件中的鏈接字符串,那么下次在字符串被訪問時所作出的變化生效,這對一個無狀態的組件來說,就象客戶再次利用組件作出了數據訪問請求一樣。
缺點

安全性。盡管asp.net internet 服務器應用程序編程接口(isapi)dll阻止了客戶直接訪問帶.config擴展名的文件,并且ntfs文件系統權限也用于進一步限制訪問,但你可能仍希望避免以明文方式將這些內容存儲在前端的web服務器上。要增加安全性,需將鏈接字符串以加密格式存儲在配置文件中。

更多信息

利用system.configuration.configurationsettings類的appsettings靜態屬性,可以獲取應用程序的定制設置。如下面的代碼片段所示,此處假定先前示例的定置關鍵字為dbconnstr。

using system.configuration;
private string getdbaseconnectionstring()
{
return configurationsettings.appsettings["dbconnstr"];
}
關于配置.net 框架應用程序的更多信息,見http://msdn.microsoft.com/library/en-us/cpguide/html/cpconconfiguringnetframeworkapplications.asp.

使用udl文件

ole db .net數據供應器支持在它的鏈接字符串中使用統一數據鏈接(udl)文件名。可以以構建參數的形式將鏈接字符串傳給oledbconnection對象,或利用對象的connectionstring屬性設置鏈接字符串。

注意 sql server .net數據供應器不支持在它的鏈接字符串中使用udl文件。因此,只有使用ole db .net數據供應器,此方法才有效。

對于ole db 供應器,要利用鏈接字符串引用udl文件,使用“file name=name.udl.”。

優點

標準方法。你也許已經在用udl文件進行鏈接字符串的管理了。

缺點

性能。每次打開鏈接時,包含udls的鏈接字符串都被讀取并被解析。
安全性。udl文件以純文本格式存儲。利用nfts文件權限可以確保這些文件的安全性,但這樣做將引發與使用.config文件相同的問題。
sqlclient對象不支持udl文件。此方法不被 sql server .net數據供應器所支持,而你要用此供應器訪問 sql server 7.0及其以后版本。
更多信息

必須確保管理員擁有該文件的讀/寫訪問權限以便進行管理,并且還要確保運行應用程序的身份擁有讀權限。對于asp.net web應用程序,應用程序工作者進程默認是以system帳號運行的,但利用機器范圍的配置文件(machine.config)中的元素可以將其覆蓋掉。利用web.config文件中的元素,及一個可選的指定帳號,可以進行冒充。
對于web應用程序,要確保沒有將udl文件放在虛目錄中,因為那樣會使該文件可通過網絡下載。
關于這些及其它與安全性相關的asp.net特性的更多信息,見http://msdn.microsoft.com/library/en-us/dnbda/html/authaspdotnet.asp.。
使用windows注冊表

可以利用定制關鍵字將鏈接字符串存儲在windows注冊表中,但由于部署問題,建議不要使用。

優點

安全性。利用訪問控制列表(acls),可以對所選的注冊表關鍵字的訪問進行管理。對更高級別的安全性,考慮對數據進行加密。
通過程序易于訪問。.net類支持從注冊表中讀取字符串。
缺點

部署。相關的注冊表設置必須同應用程序一起部署,從某種程度上抵消了xcopy部署的優點。
使用定置文件

可以使用定制文件來存儲鏈接字符串,然而這種技術沒有優點,因此并不推薦使用。

優點

沒有
缺點

額外編碼。這種方法需要額外編碼,并迫使你明確處理同時發生的問題。
部署。此文件必須同其它asp.net應用程序文件一起拷貝。避免將此文件放在asp.net應用程序的目錄或子目錄中,就可以阻止通過網絡對其進行下載。
使用構建參數和com+目錄

可以將鏈接字符串存儲在com+目錄中,并利用對象的構造字符串將它自動地傳遞給對象。com+在初始化對象,提供配置構造字符串后,將立即調用對象的construct方法。

注意這個方法只用于服務組件。只有管理組件使用了其它服務,如分布式事務處理支持或對象池化時,才考慮使用此方法。

優點

管理性。利用組件服務mmc插件,管理員可以很方便地配置鏈接字符串。
缺點

安全性。com+目錄被認為是一個不安全的存儲區(雖然利用com+角色你可以限制對它的訪問),并因此不能用于以明文維護鏈接字符串。
部署。com+目錄中的條目必須隨.net應用程序一同部署。如果使用了其它企業服務,如分布式事務或對象池化,那么將數據庫鏈接字符串存儲在目錄中不會增加部署的額外開銷,因為要支持其它服務,必須部署com+目錄。
必須為組件提供服務。可以只為所服務的組件使用構造字符串。要使能構造字符串,不能簡單地從servicedcomponent類中派生所需組件類(這將為組件提供服務)。
更多信息

關于如何為對象構造配置.net類的更多信息,見附錄中的如何為.net類使能對象構造 。
關于開發服務組件的更多信息,見http://msdn.microsoft.com/library/en-us/cpguide/html/cpconwritingservicedcomponents.asp。
鏈接使用方式

不管何種.net數據供應器,你必須總是:

盡可能晚地打開數據庫鏈接。
以盡可能短的時間使用該鏈接。
盡可能快地關閉該鏈接。鏈接直到通過close或dispose方法關閉后,它才返回到池中。即使發現它處于崩潰狀態,也應當關閉它。這樣做確保了它能返回池中,并被標記為無效。對象池周期性地掃描池,以查找已被標記為無效的對象。
為確保在方法返回前鏈接已經關閉,考慮使用下面兩個代碼片段中演示的方法。第一個示例使用了finally塊,第二個示例使用了c# using聲明,此聲明確保了對象的dispose方法被調用。

下面的代碼確保finally塊關閉了鏈接。注意,此方法只用于visual basic .net及c#中,因為visual basic .net支持結構化例外處理。

public void dosomework()
{
sqlconnection conn = new sqlconnection(connectionstring);
sqlcommand cmd = new sqlcommand("commandproc", conn );
cmd.commandtype = commandtype.storedprocedure;

try
{
conn.open();
cmd.executenonquery();
}
catch (exception e)
{
// handle and log error
}
finally
{
conn.close();
}
}

現在的代碼顯示了另外一種方法,此方法使用了c# using聲明。注意,visual basic .net并不支持using聲明,或任何功能相同的對應語句。

public void dosomework()
{
// using guarantees that dispose is called on conn, which will
// close the connection.
using (sqlconnection conn = new sqlconnection(connectionstring))
{
sqlcommand cmd = new sqlcommand("commandproc", conn);
fcmd.commandtype = commandtype.storedprocedure;
conn.open();
cmd.executequery();
}
}
此方法也適用于其它對象,如sqldatareader 或oledbdatareader,在其它任何對象對當前鏈接進行處理前,這些對象必須被關閉。

錯誤處理

ado.net錯誤生成后,將由.net框架內置的底層結構化異常處理支持所處理。結果,在數據訪問代碼中的錯誤處理方式與應用程序中其它地方的錯誤處理方式完全相同。通過標準的.net異常處理語法和技術,異常被檢測到并被處理。

本節描述了如何開發強壯的數據訪問代碼,并解釋了如何處理數據訪問錯誤。本節還提供了與sql server .net數據供應器相關的異常處理詳盡指南。

.net 異常

.net數據供應器將特定的數據庫的錯誤狀態轉化為標準的異常類型,應當在數據訪問代碼中對這些異常進行處理。通過相關的異常對象的屬性,可以獲得特定數據庫的錯誤細節。

所有.net異常類型最終是從system名稱空間的exception基類中派生的。.net數據供應器釋放特定的供應器異常類型。例如,一旦sql server 返回一個錯誤狀態時,sql server .net數據供應器釋放sqlexception對象。類似的,ole db .net數據供應器釋放 oledbexception類型的異常,此對象包含了由底層ole db供應器暴露的細節。

圖3顯示了.net數據供應器異常的層次結構。注意,oledbexception類是從 externalexception類派生的externalexception類是所有com例外的基類。對象的errorcode屬性存儲了ole db生成的com hresult。


圖3 net數據供應器層次結構

緩存并處理.net異常

要處理數據訪問例外狀態,將數據訪問代碼放在try塊中,并在catch塊中利用合適的過濾器捕獲生成的任何例外。例如,當利用sql server .net數據供應器編寫數據訪問代碼時,應當捕獲sqlexception類型的異常,如下面的代碼所示:

try
{
// data access code
}
catch (sqlexception sqlex) // more specific
{
}
catch (exception ex) // less specific
{
}
如果為不止一個catch聲明提供了不同的過濾標準,記住,按最特殊類型到最不特殊類型的順序排列它們。通過這種方式,catch塊中最特殊類型將將為任何給定的類型所執行。

sqlexception 類所暴露的屬性包含了例外狀態的細節。其中包括:

message屬性,它包含了用于描述錯誤的文本。
number屬性,它包含唯一標識錯誤類型的錯誤號。
state屬性。它包含了關于錯誤啟用狀態的附加信息。它經常用于指示特殊錯誤狀態的某個特定事件。例如,如果單一存儲過程從不止一行中生成同樣的錯誤,那么本屬性將用于標識某個具體的事件。
errors集合。它包含了sql server生成的錯誤的詳細信息。此集合部是包含至少一個sqlerror類型的對象。
下面的代碼片段演示了如何利用sql server .net數據供應器處理sql server 錯誤狀態:

using system.data;
using system.data.sqlclient;
using system.diagnostics;

// method exposed by a data access layer (dal) component
public string getproductname( int productid )
{
sqlconnection conn = new sqlconnection(
"server=(local);integrated security=sspi;database=northwind");
// enclose all data access code within a try block
try
{
conn.open();
sqlcommand cmd = new sqlcommand("lookupproductname", conn );
cmd.commandtype = commandtype.storedprocedure;

cmd.parameters.add("@productid", productid );
sqlparameter parampn =
cmd.parameters.add("@productname", sqldbtype.varchar, 40 );
parampn.direction = parameterdirection.output;

cmd.executenonquery();
// the finally code is executed before the method returns
return parampn.value.tostring();
}
catch (sqlexception sqlex)
{
// handle data access exception condition
// log specific exception details
logexception(sqlex);
// wrap the current exception in a more relevant
// outer exception and re-throw the new exception
throw new dalexception(
"unknown productid: " + productid.tostring(), sqlex );
}
catch (exception ex)
{
// handle generic exception condition . . .
throw ex;
}
finally
{
conn.close(); // ensures connection is closed
}
}

// helper routine that logs sqlexception details to the
// application event log
private void logexception( sqlexception sqlex )
{
eventlog el = new eventlog();
el.source = "customapplog";
string strmessage;
strmessage = "exception number : " + sqlex.number +
"(" + sqlex.message + ") has occurred";
el.writeentry( strmessage );

foreach (sqlerror sqle in sqlex.errors)
{
strmessage = "message: " + sqle.message +
" number: " + sqle.number +
" procedure: " + sqle.procedure +
" server: " + sqle.server +
" source: " + sqle.source +
" state: " + sqle.state +
" severity: " + sqle.class +
" linenumber: " + sqle.linenumber;
el.writeentry( strmessage );
}
}

在sqlexception catch塊中,代碼最初利用logexception幫助函數記錄錯誤狀態,此函數利用foreach聲明枚舉了errors集合中特定于供應器的細節,并將錯誤細節記錄到錯誤日志中。 catch塊中的代碼然后將特定于sql server的例外封裝在dalexception類型的對象中,這樣做對調用者的getproductname方法更具有意義。例外處理程序使用關鍵字throw將例外傳回調用者。

更多信息

關于sqlexception類成員的完整列表,見http://msdn.microsoft.com/library/en-us/cpref/html/frlrfsystemdatasqlclientsqlexceptionmemberstopic.asp。
關于定置例外的開發,.net例外的記錄與封裝,返回例外的不同方法的使用的更多信息,見http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnbda/html/exceptdotnet.asp。
從存儲過程中生成錯誤

t-sql提供了一個raiserror(注意拼寫)函數。你可用此函數生成定置錯誤,并將錯誤返回客戶。對于ado.net客戶,sql server .net數據供應器對這些數據錯誤進行解釋,并把它們轉化為sqlerror對象。

使用raiserror函數是簡單地方法是將消息文本作為第一個參數包括進來,然后指定嚴重及狀態參數,如下面的代碼片段所示:

raiserror( 'unknown product id: %s', 16, 1, @productid )

在這個例子中,替代參數用于將當前產品id作為錯誤消息文本的一部分返回,參數2是消息的嚴重性,參數3是消息狀態。

更多信息

為了避免對消息文本進行硬編碼,你可以利用sp_addmessage系統存儲過程或sql server 企業管理器將你自己的消息增加到sysmessages表中。然后你就可以使用傳遞到raiserror函數的id引用消息了。你所定義的消息ids必須大于50000,如下代碼片段所示:
raiserror( 50001, 16, 1, @productid )
關于raiserror函數的完整細節,請在sql server的在線書目中查詢raiserror。
正確使用嚴重性等級

仔細選擇錯誤嚴重性等級,并要清楚每個級別造成的沖擊。錯誤嚴重性等級的范圍是0-25,并且它用于指出sql server 2000所遇到的問題的類型。在客戶端代碼中,通過在sqlexception類的errors集合中檢查sqlerror對象的 class屬性,你可以獲得錯誤的嚴重性。表1 指出了不同嚴重性等級的意義及所造成的沖擊。

表1.錯誤嚴重性等級--沖擊及意義

嚴重性等級 鏈接已關閉 生成sqlexception對象 意義
10及其以下 no no 通知型消息,并不表示犯錯誤狀態。
11-16 no yes 可由用戶修改的錯誤,例如,使用修改后的輸入數據重試操作。
17-19 no yes 資源或系統錯誤。
20-25 yes yes 致命的系統錯誤(包括硬件錯誤)。客戶鏈接被終止。


控制自動化事務

sql server .net數據供應器對它所遇到的任何嚴重性大于10的錯誤都拋出sqlexception對象。當作為自動化(com+)事務一部分的組件檢測到sqlexception對象后,該組件必須確保它能取消事務。這也許是,也許不是自動化過程,并要依賴該方法是否已經對autocomplete屬性作出了標記。

關于在自動化事務上下文中處理對象的更多信息,見本文中的確定事務結果一節。

得到通知型消息

10及其以下嚴重性等級用于表示通知型消息,并且不會引發sqlexception對象的拋出。

要獲得通知型消息:

>創建事件處理程序,并提交給sqlconnection對象所暴露的infomessage事件。下面的代碼片段顯示了事件代理。
public delegate void sqlinfomessageeventhandler( object sender,
sqlinfomessageeventargs e );

通過傳遞到你的事件處理處理程序中的sqlinfomessageeventargs對象,可以得到消息數據。此對象暴露了errors屬性,該屬性包含一組sqlerror對象--每個通知消息一個sqlerror對象。下面的代碼片段演示了如何注冊用于記錄通知型消息的事件處理程序。

public string getproductname( int productid )
{
sqlconnection conn = new sqlconnection(
"server=(local);integrated security=sspi;database=northwind");
try
{
// register a message event handler
conn.infomessage += new sqlinfomessageeventhandler( messageeventhandler );
conn.open();
// setup command object and execute it
. . .
}
catch (sqlexception sqlex)
{
// log and handle exception
. . .
}
finally
{
conn.close();
}
}
// message event handler
void messageeventhandler( object sender, sqlinfomessageeventargs e )
{
foreach( sqlerror sqle in e.errors )
{
// log sqlerror properties
. . .
}
}

性能

本節介紹了一些常見的數據訪問方案,對每種方案,以ado.net 數據訪問代碼的形式描述了最優性能和擴展性解決方案。在合適的地方,還對性能,功能及開發最作出了比較。本節考慮了下面的功能方案。

獲取多行. 獲取一個結果集,并在得到的行中重復。
獲取一行. 獲取具有指定關鍵字的一行。
獲取一項. 從指定的行中得到一項。
確定某項數據的存在性. 檢查具有特定關鍵字的一行是否存在。這是單項查找方案的一種變體,這里返回一個簡單的布爾值就足夠了。
獲取多行

在這個方案中,你要獲取一組表格化數據,并在得到的行中重復執行某個操作。例如你得到了一組數據,并以非鏈接的方式處理,然后(可能通過web服務)將它作為xml文檔傳遞給客戶應用程序。可選的,你也可以以html表的形式將這些數據顯示出來。

為了幫助確定最合適的數據訪問方法,考慮你是否需要(非鏈接)dataset 對象的附加靈活性,還是只需要sqldatareader對象提供的原有性能,這些性能非常適合于b2c web應用程序的數據表示。圖4顯示了這兩種基本場景。

注意用于填充dataset的sqldataadapter利用sqldatareader方法數據。


圖4 多行數據訪問方案

方法比較

當從數據源中獲取多行時,你可以使用下面的方法:

使用sqldataadapter對象生成dataset 或 datatabl對象。
利用sqldatareader對象提供只讀的只向前的數據流。
利用xmlreader對象提供只讀的只向前的xml數據流。
sqldatareader 與 dataset/datatable間的選擇本質上是性能與功能間的選擇。sqldatareader 提供了最優性能,而dataset提供了額外的功能與靈活性。

數據綁定

所有這三個對象都可以作為數據綁定控件的數據源。而dataset 和 datatable 可作為更廣范圍控件的數據源。這是因為dataset 和 datatable 實現了(生成ilist接口)ilistsource接口,而sqldatareader 實現了ienumerable接口。許多能進行數據綁定的winform控件需要實現了ilist接口的數據源。

這種不同是因為為每種對象類型設計的場景類型不同。dataset (它包含 datatable)是一個豐富的、非鏈接結構,它適合于web和桌面(winform)應用程序。另一方面,數據閱讀器已經為web應用程序進行了優化,這種應用程序需要優化的、只能向前的數據訪問。

檢查將要綁定到的特定控件類型的數據源需求。

在應用程序層間傳遞數據

dataset提供了可作為xml被任意操縱數據的關系圖,并允許數據的非鏈接緩存拷貝在應用程序層與組件間傳遞。然而,sqldatareader提供了更優化的性能,因為它避免了與創建dataset相關的性能及內存開銷。記住,dataset對象的創建將導致多個子對象--包括datatable, datarow 和datacolumn--及作為這些子對象容器的集合對象的創建。

使用dataset

使用sqldataadapter填充的dataset對象,當:

你需要非鏈接的駐留內存的緩存數據,以便你能將它傳遞到其它組件或應用程序中的其它層。
你需要內存中的數據關系圖以執行xml或非xml操作。
你正在使用的數據來自多個數據源,如多個數據庫、表或文件。
你希望更新獲得的一些或所有行,并希望利用sqldataadapter的批更新功能。
你要對控件綁定數據,而此控件需要支持ilist接口的數據源。
更多信息

如果使用sqldataadapter生成dataset 或 datatable,需注意:

不必明確打開或關閉數據庫鏈接。sqldataadapter fill方法打開數據庫鏈接,并在此方法返回前關閉該鏈接。如果鏈接原來已經打開,那么此方法仍使鏈接處于打開狀態。
如果出于其它目的需要鏈接,那么考慮在調用fill方法前打開鏈接。這樣你就可以避免不必要的打開/關閉操作,提高性能。
盡管能重復使用同一sqlcommand對象多執行同樣的命令,但不要重復使用此對象執行不同的命令。
關于如何利用sqldataadapter對象填充dataset 或 datatable對象的代碼示例,見附錄中的如何利用sqldataadapter 對象獲得多行。
使用sqldatareader

些劣情況,可以使用通過調用 sqlcommand 對象的executereader方法得到的sqldatareader對象:

正在處理大量數據時--太多了而不能在單個緩沖區內維護。
希望減少應用程序在內存中的印跡。
希望避免與dataset對象創建相關的開銷。
希望對某控件執行數據綁定操作,而此控件支持實現了ienumerable接口的數據源。
希望流水線化數據訪問,并對其優化。
正在讀取包含二進制大對象(blob)列的行。你可以使用sqldatareader對象以可管理的大塊為單位從數據庫中將blob數據拉出來,而不是一次性地將所有數據提取出來。關于處理blob數據的更多細節,見本文處理blobs 一節。
更多信息

如果使用sqldatareader對象,請注意:

在數據閱讀器活動期間,底層的數據庫鏈接保持打開,并不能用于其它任何目的。盡可能早地對sqldatareader對象調用close方法。
每個鏈接只能有一個數據閱讀器。
通過向executereader方法傳遞commandbehavior.closeconnection枚舉值,可以在使用完數據閱讀器后,明確地關閉鏈接;或者,將鏈接生命周期綁定到sqldatareader對象。這預示著當sqldatareader對象關閉時,鏈接也將關閉。
在利用閱讀器訪問數據時,如果你知道列的底層數據類型,那么就應使用類型化存取器方法(如getint32 和 getstring),這是因為在讀取列數據時,這些方法減少了讀取列數據所需的類型轉換量。
為避免將不必要的數據從服務器發送到客戶端,如果你要關閉閱讀器并拋棄所有保留的結果,那么在對閱讀器調用close方法前調用命令對象的cancel方法。cancel方法確保了服務器的結果被拋棄,而不會被發送到客戶端。相反,對數據閱讀器調用close方法會使閱讀器不必要地提取出保留的結果,以清空數據流。
如果要得到從存儲過程返回的輸出值或返回值,并且你在利用sqlcommand對象的executereader方法,那么在得到輸出或返回值前,必須對閱讀器調用close方法。
關于演示如何利用sqldatareader對象的代碼示例,附錄中的如何利用sqldatareader對象獲取多行數據。
使用xmlreader

下列情況下,使用通過調用sqlcommand對象的executexmlreader方法得到的xmlreader對象:

希望將得到的數據作為xml 處理,但不希望引發因創建dataset對象而造成的額外性能開銷,并且不需要數據的非鏈接緩存。
希望利用sql server for xml 語法的功能,這種語法允許以靈活的方式從數據庫中得到xml片段(即,不帶根元素的xml文檔)。例如,這種方法使你能夠精確指定元素名,是使用元素還是使用以屬性為核心的圖解,圖解是否隨xml數據一起被返回,等等。
更多信息

如果使用xmlreader,請注意:

在從xmlreader對象中讀取數據時,鏈接必須保持打開。sqlcommand對象的 executexmlreader方法目前不支持commandbehavior.closeconnection枚舉值,因此在使用完閱讀器后必須明確關閉鏈接。
對于如何使用xmlreader對象的代碼示例,見附錄中的如何利用 xmlreader獲取多行數據。
獲取單行數據

在這種場景中,將從數據源中獲取包含一組指定列的單行數據。例如,你得到一個客戶id,并希望查找與客戶相關的細節;或得到一個產品id,并希望得到產品信息。

方法比較

如果要對從數據源中得到的一行數據執行綁定操作,可以用sqldataadapter對象填充dataset 或datatable對象,其方式與在先前討論過的獲取多行數據及重復場景中描述的方式相同。然而,除非特別需要dataset 或datatable對象的功能,否則應當避免創建這些對象。

如果需要獲取單行數據,那么請使用下面的一種方法:

使用存儲過程輸出參數.
使用sqldatareader對象.
這兩種方法都避免了在服務器端創建結果集,在客戶端創建dataset對象的不必要額外開銷。每種方法的相對性能要依賴于強度等級及數據庫鏈接池化是否被使能。當數據庫鏈接池化使能時,性能測試表明存儲過程方法在高強度環境下(同時存在200多鏈接)其性能比sqldatareader方法高近30%。

使用存儲過程輸出參數

如下情況中使用存儲過程輸出參數:

要從鏈接池化使能的多層web應用程序中獲得一行數據。
更多信息

關于演示如何使用存儲過程輸出參數的代碼示例,見附錄中的使用存儲過程輸出參數獲取一行數據。
使用sqldatareader對象

下列情況,需使用sqldatareader對象:

除了數據值,還需要元數據時。可以利用數據閱讀器的getschematable方法獲取列元數據。
未使用鏈接池化時。在鏈接池化無效時,sqldatareader對象在所有強度環境下都是好方式;性能測試表明,在200瀏覽器鏈接時,此方法比存儲過程方法在性能上要高約20%。
更多信息

如果知道查詢結果只需返回一行,那么在調用sqlcommand對象的executereader 方法時,使用commandbehavior.singlerow枚舉值。一些供應器,如ole db .net數據供應器,用此技巧來優化性能。例如,供應器使用irow接口(如果此接口存在)而不是代價更高的irowset接口。這個參數對sql server .net數據供應器沒有影響。
在使用sqldatareader對象時,總是應當通過sqldatareader對象的類型化存取器方法,如getstring 和getdecimal,獲得輸出參數。這樣做就避免了不必要的類型轉換。
關于如何使用sqldatareader對象獲取單行數據的代碼示例,見附錄中的如何使用 sqldatareader對象獲取單行數據。
獲取單項數據

在本場景中,要獲取單項數據。例如,提供了產品id后,希望查詢單一的產品名;或,給出了客戶名后,希望查詢客戶的信用等級。在這種場景中,為得到單項數據,通常不希望引發創建dataset 對象或甚至是 datatable對象的額外開銷。

也許只希望檢查數據庫中是否存在特定的行。例如,當新用戶在網站注冊時,需要檢查所選用戶名是否已經存在。這是單項數據查詢中很特殊的例子,但在此例子中,返回一個簡單的布爾返回值就足夠了。

方法比較

當從數據源獲取單項數據時,考慮下面的方法:

同存儲過程一起使用sqlcommand對象的executescalar方法。
使用存儲過程輸出或返回參數。
使用sqldatareader對象。
executescalar方法直接返回數據項,因為它是為只返回單個值的查詢設計的,與存儲過程輸出參數和sqldatareader方法相比,它需要更少的代碼。

從性能方面來說,應當使用存儲過程輸出或返回參數,因為測試結果表明,存儲過程方法在從低強度到高強度環境中(從同時不到100瀏覽器鏈接到200瀏覽器鏈接)提供了一致的性能。

更多信息

如果通過executequery方法所執行的查詢返回多列和/或行,那么此方法只返回第一行的第一列。
關于演示如何使用executescalar方法的代碼片段,見附錄中的如何使用 executescalar獲取單項數據。
關于演示如何利用存儲過程輸出或返回參數獲取單項數據的代碼示例,見附錄中的如何利用存儲過程輸出或返回參數獲取單項數據
關于演示如何使用sqldatareader對象獲取單項數據的代碼示例,見附錄中的如何使用 sqldatareader對象獲取單項數據。
通過防火墻建立鏈接

需要經常配置互聯網應用程序以使它能夠通過防火墻鏈接到sql server。例如,許多web應用程序及防火墻的主要結構組件是周邊網絡(也被稱為dmz或非軍事化區),它們用于隔離高端web服務器與內部網絡。

通過防火墻鏈接到sql server時,需要對防火墻,客戶和服務器進行明確配置。sql server提供了客戶網絡應用程序和服務器網絡應用程序以幫助進行配置。

選擇網絡庫

當通過防火墻建立鏈接時,使用sql server tcp/ip網絡庫來簡化配置,這是sql server2000安裝的默認選項。如果使用先前版本的sql server,那么分別利用客戶端網絡應用程序和服務器端網絡應用程序檢查tcp/ip是否在客戶和服務器端已經被配置為默認的網絡庫。

除了配置優點,使用tcp/ip庫還意味著:

受益于大宗數據的改進性能和增加的擴展性。
避免與指定管道相關的附加安全信息。
必須在客戶和服務器計算機上配置tcp/ip,因為大多數防火墻限制了流量通過的端口,所以必須仔細考慮sql server所使用的端口號。

配置服務器

sql server的默認實例監聽1433端口。然而,sql server 2000的指定實例在它們首次開啟時,動態地分配端口號。網絡管理員有希望在防火墻打開一定范圍的端口;因此,當隨防火墻使用sql server的指定實例時,利用服務網絡應用程序對實例進行配置,使它監聽特定的端口。然后管理員對防火墻進行配置,以使防火墻允許流量到達特定的ip地址及服務器實例所監聽的端口。

注意,客戶端網絡庫所使用的源端口號在1024-5000間動態分配。這是tcp/ip客戶端應用程序的標準作法,但這意味著防火墻必須允許途經此范圍的任何端口流量能夠通過。關于sql server所使用的端口的更多信息,在微軟產品支持服務網站上,參見inf: p 通過防火墻對sql server進行通訊所需的tcp端口 。。

動態查找指定實例

如果改變了sql server所監聽的默認端口,那么就要對客戶端進行配置,以使它鏈接到此端口。更多細節,見本文中的配置客戶端 一節。

如果改變了sql server 2000默認實例的端口號,那么不修改客戶端將導致鏈接錯誤。如果存在多個sql server 實例,最新版本的mdac數據訪問堆棧(2.6)將進行動態查找,并利用用戶數據報協議(udp)協商(通過udp端口1434)對指定實例進行定位。盡管這種方法在開發環境下也許有效,但在現在環境中卻不大可能正常工作,因為典型發問下防火墻阻止udp協商流量的通過。

為了避開這種情況,總是將客戶端配置為鏈接到已配置好的目的端口號。

配置客戶端

應當對客戶端進行配置以利用tcp/ip網絡庫鏈接到sql server,并且也應當確保客戶端庫使用了正確的目的端口號。

使用tcp/ip 網絡庫

利用sql server客戶端網絡庫,可以對客戶端進行配置。在某些安裝版本中,可能沒有將這個應用程序安裝到客戶端(如web服務器)。在這種情況下,可以按如下方式之一解決:

利用通過鏈接字符串提供的“network library=dbmssocn”名稱-值對指定網絡庫。字符串dbmssocn用于標識tcp/ip(套接字)庫。
注意 在使用sql server .net數據供應器時,網絡庫的默認設置是使用“dbmssocn”。

在客戶端機器上修改注冊表,把tcp/ip設置為默認庫。關于配置sql server網絡庫的更多信息,參見howto: 不使用客戶端網絡應用程序而修改sql server默認網絡庫(q250550)。
指定端口

如果sql server的實例被配置為監聽默認的1433以外的其它端口,那么通過以下操作,就能指定鏈接到的端口號:

使用客戶端網絡應用程序
利用提供給鏈接字符串的“server”或“data source”名稱-值對來指定端口號。要按下面的格式使用字符串:
"data source=servername,portnumber"
注意 servername可以是ip地址,或域名系統(dns)名,為了優化性能,可以使用ip 地址以避免dns 查詢。

分布式事務處理

如果開發了使用com+分布式事務處理和微軟分布式事務處理協調器(dtc)服務的服務組件,那么就需要對防火墻進行配置,以允許dtc流在不同dtc實例間及dtc與資源管理器(例如sql server)間流動。

有關為dtc開放端口的更多信息,見info:為通過防火墻工作,配置微軟分布式事務處理協調器 (dtc)。

處理blobs

目前,很多應用程序除了處理許多傳統的字符串和數字型數據外,還要處理象圖形或聲音--甚至復雜的數據格式,如視頻格式的數據。圖形、聲音與視頻的數據格式類型不一。然而從存儲角度來說,它們都可被視為二進制數據塊,通常將其稱為blobs(二進制大對象)。

sql server提供了binary, varbinary, 和image數據格式來存儲blobs。不考慮名稱,blob數據也可被稱為基于文件的數據。例如,你可能要存儲與特定行相關的二進制長注釋字段。sql server為此目的提供了ntext 和text數據類型。

通常,對于小于8kb的二進制數據,使用varbinary數據類型。對于超過此大小的二進制數據,使用image 。表2 匯集了每個數據類型的主要特性。

表2 數據類型特性

數據類型 大小 描述
binary 范圍從1-8kb。存儲大小是指定大小加4字節。 固定長度的二進制數據
varbinary 范圍從1-8kb。存儲大小是所提供數據的實際大小加4字節。 可變長度的二進制數據
image 從0-2gb大小的可變長度二進制數據 大容量可變長度二進制數據
text 從0-2gb大小的可變長度數據 字符型數據
ntext 從0-2gb大小的可變長度數據 寬字節字符數據


何處存儲blob數據

sql server 7.0及其以后版本已經提高了存儲在數據庫中的blob數據的使用性能。這種情況的一個原因是數據庫頁面大小已經增加到了8kb。結果,小于8kb的文本或圖象數據不必再存儲在頁面單獨的二進制樹結構中,而是能被存儲在單行中。這意味著讀取和寫入text, ntext, 或 image數據能象讀取或寫入字符或二進制字符串那樣快。超出8kb后,將在行中建立一個指針,數據本身存儲在獨立數據頁面的二進制樹結構中,這不可避免會對性能產生沖擊。

關于迫使text, ntext, 和 image數據存儲在單行中的更多信息,見sql server在線圖書中的使用text和image數據主題。

一個經常使用的處理blob數據的可選方法是,將blob數據存儲在文件系統中,并在數據庫列中存儲一個指針(通常是一個統一資源定位器--url鏈接)以引用正確的文件。對于sql server 7.0以前的版本,將blob數據存儲在數據庫外的文件系統中,可以提高性能。

然而,sql server 2000改進了blob支持,以及ado.net對讀取和寫入blob數據的支持,使在數據庫中存儲blob數據成為一種可行的方法。

在數據庫中存儲blob 數據的優點

將blob數據存儲在數據庫中,帶來了很多優點:

易于保持blob數據與行中其它項數據的同步。
blob數據由數據庫所支持,擁有單一的存儲流,易于管理。
通過sql server 2000所支持的xml可以訪問blob數據,這將在xml流中返回64位編碼描述的數據。
對包含了固定或可變長度的字符(包括寬字符)數據的列可以執行sql server全文本搜索(fts)操作。也可以對包含在image字段中的已格式化的基于文本的數據--word 或 excel文檔--執行fts操作。
將blob數據寫入到數據庫中

下面的代碼演示了如何利用ado.net將從某個文件獲得的二進制數據寫入sql server image字段中。

public void storepicture( string filename )
{
// read the file into a byte array
filestream fs = new filestream( filename, filemode.open, fileaccess.read );
byte[] imagedata = new byte[fs.length];
fs.read( imagedata, 0, (int)fs.length );
fs.close();

sqlconnection conn = new sqlconnection("");
sqlcommand cmd = new sqlcommand("storepicture", conn);
cmd.commandtype = commandtype.storedprocedure;
cmd.parameters.add("@filename", filename );
cmd.parameters["@filename"].direction = parameterdirection.input;
cmd.parameters.add("@blobdata", sqldbtype.image);
cmd.parameters["@blobdata"].direction = parameterdirection.input;
// store the byte array within the image field
cmd.parameters["@blobdata"].value = imagedata;
try
{
conn.open();
cmd.executenonquery();
}
catch
{
throw;
}
finally
{
conn.close();
}
}

從數據庫中讀取blob數據

在通過executereader方法創建sqldatareader對象以讀取包含blob數據的行時,需使用commandbehavior.sequentialaccess枚舉值。如果沒有此枚舉值,閱讀器一次只從服務器中向客戶端發送一行數據。如果行包含了bolb數據,這預示著要占用大量內存。通過利用枚舉值,就獲得了更好的控制權,因為blob數據只在被引用時才被發出(例如,利用getbytes方法,可以控制讀取的字節數)。這在下面的代碼片段中進行了演示。

// assume previously established command and connection
// the command selects the image column from the table
conn.open();
sqldatareader reader = cmd.executereader(commandbehavior.sequentialaccess);
reader.read();
// get size of image data - pass null as the byte array parameter
long bytesize = reader.getbytes(0, 0, null, 0, 0);
// allocate byte array to hold image data
byte[] imagedata = new byte[bytesize];
long bytesread = 0;
int curpos = 0;
while (bytesread < bytesize)
{
// chunksize is an arbitrary application defined value
bytesread += reader.getbytes(0, curpos, imagedata, curpos, chunksize);
curpos += chunksize;
}
// byte array 'imagedata' now contains blob from database

注意使用commandbehavior.sequentialaccess需要以嚴格的順序訪問列數據。例如,如果blob數據存在于第3列,并且還需要從第1,2列中讀取數據,那么在讀取第3列前必須先讀取第1,2列。

事務處理

實際上所有用于更新數據源的面向商業的應用程序都需要事務處理支持。通過提供四個基本擔保,即眾所周知的首字縮寫acid:可分性,一致性,分離性,和耐久性,事務處理將用于確保包含在一個或多個數據源中的系統的完整性。

例如,考慮一個基于web的零售應用程序,它用于處理購買訂單。每個訂單需要3個完全不同操作,這些操作涉及到3個數據庫更新:

庫存水準必須減少所訂購的數量。
所購買的量必須記入客戶的信用等級。
新訂單必須增加到數據庫中。
這三個不同的操作作為一個單元并自動執行是至關重要的。三個操作必須全部成功,或都不成功--任何一個操作出現誤差都將破壞數據完整性。事務處理提供了這種完整性及其它保證。

要進一步了解事務處理過程的基本原則,見http://msdn.microsoft.com/library/en-us/cpguide/html/cpcontransactionprocessingfundamentals.asp。

可以采用很多方法將事務管理合并到數據訪問代碼中。每種方法適合下面兩種基本編程模型之一。

手工事務處理。可以直接在組件代碼或存儲過程中分別編寫利用ado.net 或 transact-sql事務處理支持特性的代碼。
自動化(com+)事務處理。可以向.net類中增加聲明在運行時指定對象事務處理需要的屬性。這種模型使你能方便地配置多個組件以使它們在同一事務處理內運行。
盡管自動化事務處理模型極大地簡化了分布式事務處理過程,但兩種模型都用于執行本地事務處理(即對單個資源管理器如sql server 2000執行的事務處理)或分布式事務處理(即,對位于遠程計算機上的多個資源管理執行的事務處理)。

你也許會試圖利用自動化(com+)事務處理來從易于編程的模型中獲益。在有多個組件執行數據庫更新的系統中,這種優點更明顯。然而,在很多情況下,應當避免這種事務處理模型所帶來的額外開銷和性能損失。

本節將指導你根據特定的應用程序環境選擇最合適的模型。

選擇事務處理模型

在選擇事務處理模型前,首先應當考慮是否真正需要事務處理。事務處理是服務器應用程序使用的最昂貴的資源,在不必要使用的地方,它們降低了擴展性。考慮下面用于管理事務處理使用的準則:

只在需要跨一組操作獲取鎖并需要加強acid規則時才執行事務處理。
盡可能短地保持事務處理,以最小化維持數據庫鎖的時間。
永遠不要將客戶放到事務處理生命周期的控制之中。
不要為單個sql語句使用事務處理。sql server自動把每個語句作為單個事務處理執行。
自動化事務處理與手工事務處理的對比

盡管編程模型已經對自動化事務處理進行了簡化,特別是在多個組件執行數據庫更新時,但本地事務處理總是相當快,因為它們不需要與微軟dtc交互。即使你對單個本地資源管理器(如sql server)使用自動化事務處理,也是這種情況(盡管性能損失減少了),因為手式本地事務處理避免了所有不必要的與dtc的進程間通信。

對于下面的情況,需使用手工事務處理:

對單個數據庫執行事務處理。
對于下列情況,則宜使用自動事務處理:

需要將單個事務處理擴展到多個遠程數據庫時。
需要單個事務處理擁有多個資源管理器(如數據庫和windows 2000消息隊列(被稱為msmq)資源管理器)時。
注意 避免混用事務處理模型。最好只使用其中一個。

在性能足夠好的應用程序環境中,(甚至對于單個數據庫)選擇自動化事務處理以簡化編程模型,這種做法是合理的。自動化事務處理使多個組件能很容易地執行現一事務處理中的多個操作。

使用手工事務處理

對于手工事務處理,可以直接在組件代碼或存儲過程中分別編寫使用ado.net 或 transact-sql事務處理支持特性的代碼。多數情況下,應選擇在存儲過程中控制事務處理,因為這種方法提供了更高的封裝性,并且在性能方面,此方法與利用ado.net 代碼執行事務處理兼容。

利用ado.net執行手工事務處理

ado.net支持事務處理對象,利用此對象可以開始新事務處理過程,并明確控制事務處理是否執行還是回滾。事務處理對象與單個數據庫鏈接相關,可以通過鏈接對象的begintransaction方法獲得。調用此方法并不是暗示,接下來的命令是在事務處理上下文中發出的。必須通過設置命令的transaction屬性,明確地將每個命令與事務處理關聯起來。可以將多個命令對象與事務處理對象關聯,因此在單個事務處理中就針對單個數據庫把多個操作進行分組。

關于使用ado.net事務處理代碼的示例,見附錄中如何編碼ado.net手工事務處理。

更多信息

ado.net手工事務處理的默認分離級別是讀聯鎖,這意味著在讀取數據時,數據庫控制共享鎖,但在事務處理結束前,數據可以被修改。這種情況潛在地會產生不可重復的讀取或虛數據。通過將事務處理對象的isolationlevel屬性設置為isolationlevel枚舉類型所定義的一個枚舉值,就可改變分離級別。
必須仔細為事務處理選擇合適的分離級別。其折衷是數據一致性與性能的比例。最高的分離等級(被序列化了)提供了絕對的數據一致性,但是以系統整體吞吐量為代價。較低的分離等級會使應用程序更易于擴展,但同時增加了因數據不一致而導致出錯的可能性。對多數時間讀取數據、極少寫入數據的系統來說,較低的分離等級是合適的。
關于選擇恰當事務處理級別極有價值的信息,見微軟出版社名為inside sql server 2000的書,作者kalen delaney。
利用存儲過程執行手工事務處理

也可以在存儲過程中使用transact-sql語句直接控制手工事務處理。例如,可以利用包含了transact-sql事務處理語句(如begin transaction、end transaction及rollback transaction)的存儲過程執行事務處理。

更多信息

如果需要,可以在存儲過程中使用set transaction isolation level語句控制事務處理的分離等級。讀聯鎖是sql server的默認設置。關于sql server分離級別的更多信息,見sql server在線書目“訪問和修改關系數據”一節中的分離級別部分。
關于演示如何利用transact-sql事務處理語句執行事務更新的代碼示例,見附錄中的如何利用transact-sql執行事務處理。注冊會員,創建你的web開發資料庫,
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 怀柔区| 吐鲁番市| 沙坪坝区| 麻栗坡县| 家居| 合肥市| 大埔县| 景德镇市| 巴彦淖尔市| 都江堰市| 金华市| 岢岚县| 临朐县| 万宁市| 莱阳市| 大渡口区| 班戈县| 荥经县| 巧家县| 兴山县| 大田县| 龙胜| 天等县| 珲春市| 尼木县| 荆门市| 庄浪县| 巧家县| 墨竹工卡县| 稷山县| 周口市| 廉江市| 浦北县| 凤冈县| 花莲市| 旬邑县| 邻水| 和顺县| 民县| 金阳县| 天全县|