終于和CLR成了一家人
CLR的集成
通過集成CLR,SQL Server 2005已經獲得了很多新的特性,借助CLR的集成可以用任何.NET語言建立存儲過程、觸發器、用戶自定義函數、用戶自定義類型、用戶自定義聚合。通過這個集成筆者認為SQL Server主要可以獲得如下優勢。
提供了一個更加完善的開發模型,對于熟悉面向對象的開發人員和一直在SQL Server平臺進行T-SQL開發的開發人員都提供開發的舞臺。更深層次講,這兩類開發人員可以根據自己熟悉的領域對應用進行優化,T-SQL開發人員可以根據執行計劃分析和優化應用,面向對象開發人員可以根據已有的Best Practice,借助代碼復查以優化自己的應用。
提供了更好的安全性,這個主要來源于CLR運行于托管環境的原因,通過運行過程中CAS(Code-Aclearcase/" target="_blank" >ccess Security),所有的代碼執行過程都是在一個安全的調用鏈運行,與以往不同的是,即便用戶獲得了某個已開發好的功能的使用權限,但是如果該功能所使用的某個組件的安全性與目標資源的安全性相沖突,也會被CLR判斷為非法。
以往的代碼面臨的主要安全問題如下:
1. 非授權使用或者越權使用;
2. 代碼注入;
3. 額外信息泄漏;
4. 偽裝、欺騙代碼執行;
圖1:執行過程中代碼主要面臨的安全問題
那么在CLR中,執行每一個Assembly的時候都要基于既有的或者定制的安全策略進行訪問檢查,不僅僅是調用者權限檢查,也包括用戶與目標資源之間的訪問關系,更為主要的是在每個功能調用的過程中,還要檢查每上游組件的安全要求是否與自身安全要求抵觸,如果出現異常,那么這個調用鏈也會被終止。執行過程如下:
圖2:單個Assembly的執行過程
圖3:Assembly調用鏈的安全檢查
這樣做的好處在于:可以大大豐富SQL Server的對象系統。
相信很多T-SQL設計人員在進行數據庫設計的時候,會碰到因為相對非常有限的數據類型無法描述業務對象的情況。但有了CLR的支持,SQL Server 2005可以描述的對象系統基本上擴展為無限。但是,筆者這里根據經驗提醒用戶在使用該功能的時候要注意如下幾個內容:
1. 設計新的數據對象要考慮到中間結果的存儲問題。
2. 涉及到查詢的時候還是要考慮采用T-SQL,這主要是出于效率問題。
3. 盡可能考慮到事件、Delegate回調對于處理性能的影響,不是必要的話盡量不用。
可以把整個開發的流程完全集成到統一的Visual Studio 2005中,全開發生命期可以在一個框架下完成。
更深層次講,在完成統一個項目的時候,可以充分利用CLR進行復雜數據結構的計算能力效率和T-SQL的關系數據處理能力優勢。
圖3:CLR支持后擴展數據對象的資源分布
相對而言,開發User-Function和User-Defined Procedure都是比較容易,這里筆者就開發CLR 觸發器作些說明。正如大家所知,Trigger主要包括兩類:“DML 觸發器”和“DDL 觸發器”。DML觸發器主要在DELETE、UPDATE、INSERT的時候觸發,DDL 觸發器則會在CREATE、ALTER、DROP的時候觸發。在使用T-SQL編寫觸發器的時候可以通過INSERTED和DELETED這兩個虛表,結合COLUMN_UPDATED()函數完成DML事件的響應。在集成了CLR之后,用.NET語言寫觸發器可以訪問如下內容:
繼續訪問DELETED和INSERTED這兩個虛表;
通過UPDATE操作,判斷哪些列受到了修改;
通過訪問數據庫對象獲得DDL的執行語句;
除此而外,開發CLR 觸發器的時候還可以通過SqlContext.TriggerContext獲得當前操作的上下文,明確究竟是DML的INSERT、UPDATE、DELETE,還是DDL的CREATE、DROP、ALTER操作。
代碼示例1:INSERT或DELETE操作的DML觸發器寫法
SqlConnection connection = new SqlConnection ("context connection = true"); connection.Open(); SqlCommand command = connection.CreateCommand(); command.CommandText = "SELECT * from " + "inserted";
代碼實例2:判斷哪些列被UPDATE
reader = command.ExecuteReader(); reader.Read(); for (int columnNumber = 0; columnNumber < triggContext.ColumnCount; columnNumber++) { pipe.Send("Updated column " + reader.GetName(columnNumber) + "? " + triggContext.IsUpdatedColumn(columnNumber).ToString()); } reader.Close();
using System; using System.Data; using System.Data.Sql; using Microsoft.SqlServer.Server; using System.Data.SqlClient; using System.Data.SqlTypes; using System.Xml; using System.Text.RegularExpressions; public class CLRTriggers { public static void DropTableTrigger() { SqlTriggerContext triggContext = SqlContext.TriggerContext; switch(triggContext.TriggerAction) { case TriggerAction.DropTable: SqlContext.Pipe.Send("Table dropped! Here's the EventData:"); SqlContext.Pipe.Send(triggContext.EventData.Value); break; default: SqlContext.Pipe.Send("Something happened! Here's the EventData:"); SqlContext.Pipe.Send(triggContext.EventData.Value); break; } } }
SQL Server 2005上的ADO.NET 2.0
SQL Server 2005對于應用開發業提供了一系列新的功能,不過很多需要通過ADO.NET 2.0來訪問。根據筆者的經驗,如果您確定您的產品或者項目依托于SQL Server 2005,而不是做數據庫產品無關的通用產品的話,完全可以考慮這些新的特性,但是要注意這些特性很可能會改變您的很多應用架構。
不會影響到系統構架的新特性如下:
(1)新的數據類型,包括XML數據;
(2)支持Snapshot級的事務隔離級別;
(3) 支持系統快速高可用功能的Mirroring;
但是,下面一些功能將會影響到您的系統架構:
(1)一步的SQL Server訪問
(2)MARS (Multiple Active Result Set),不僅可以讓您復用與數據庫的連接,而且還可以在源數據更新的時候,主動根據SQL Server觸發更新。
事務的控制上,ADO.NET 2.0可以借助SQL Server自己的事務機制或者System.Transactions的支持,可以用非常簡單的方式使用本地或者分布式事務。如果你的數據操作僅僅限于當前一個固定的SQL Server,那么筆者建議您采用Promotion的輕量級交易機制。你所要做的就是在SqlConnection的ConnectionString屬性定義時增加一個Enlist關鍵字即可,這樣當你的ADO.NET訪問涉及DML操作時,CLR會自動為您增加一個事務,保證操作的原子性。但如果你的操作不僅僅限于當前SQL Server,還要訪問其他異構數據庫或者隊列之類的其他對象,那么您需要分布式事務的支持,這時候您需要在DTC的調度下,同時使用SQL Server 2005本地事務、System.Transactions和System.Data.SqlClient三者,把整個處理包裝到一個代價比較昂貴的分布式交易中??偠灾?,到底要使用那種事務處理,要看您的應用需要。
筆者要提醒您注意的是,在CLR的托管代碼支持下,SQL Server 2005采用CLR 事務和T-SQL的事務有很大的區別:
CLR中定義的包括事務的處理內容必須被ROLLBACK或者COMMIT,除非SQL Server在處理內容沒有執行結束之前出現嚴重錯誤,導致內容不能執行結束。
(1)出現事務嵌套時,內部事務不可以ROLLBACK或者COMMIT外部的事務。
(2)不要試圖提交非本Function或者Procedure的事務,這樣會導致Run-Time Error。
(3) 試圖回退非本Function或者Procedure的事務時,會導致事務執行掛起,借助該特性可以用來調試事務內部的內容。
XML的串行化支持
SQL Server 2000僅僅提供了有限的HTTP直接訪問支持,但是在引入了CLR 集成后,Internet / Intranet應用可以借助于XML串行化,直接以XML方式訪問系統的用戶自定義類型數據,尤其對于給予HTTP訪問BLOB對象的時候也可以支持,此外可以在SQL Server內部通過該特性訪問Web Service。
原文轉自:http://www.anti-gravitydesign.com