您正在看的SQLserver教程是:功能強大的全新 T-SQL 語法極大地提升了 SQL Server 的可編程性。 錯誤處理 SNAPSHOT 隔離 WAITFOR 命令 BULK 行集提供程序 TOP 選項 APPLY 運算符 通用表表達式和遞歸查詢 PIVOT 運算符 觸發器和通知 小結
SQL Server 下一版本 — 代號“Yukon”的 Beta 1 版引入了許多對 T-SQL 的功能增強和新增功能,可以提高您的表達能力、錯誤管理水平和性能。本文中,我將討論一些重要的功能增強和新功能,包括錯誤處理、遞歸查詢和隔離。我將把注意力主要放在錯誤管理和相關的改進,並簡要描述其他方面的功能增強。
除了這裡敘述的功能以外,T-SQL 還有許多其他重要功能增強我沒有深入探討,因為其中一些從概念上講並不新,而另一些又需要單獨討論。這些方面包括消息處理和服務代理平台,分區和 XML 的功能增強。(有關 Yukon 中 XML 功能增強的更多信息,請參閱本期中 Bob Beauchemin 撰寫的“XML in Yukon: New Version Showcases Native XML Type and Advanced Data Handling”一文。)
SQL Server Yukon Beta 1 為在 T-SQL 中進行錯誤處理引入了新的 TRY/CATCH 構造。此構造可以用於捕獲事務中止錯誤,甚至是在 SQL Server 以前的版本中會引起批處理中止的錯誤(轉換錯誤、死鎖等)。新的構造無法處理的錯誤類型是那些會導致會話中止的錯誤(通常是嚴重度為 21 和更高的錯誤,如硬件錯誤)。通常,您的錯誤處理代碼如圖 1 中所示。
XACT_ABORT 設置打開了,這樣 SQL Server 可以將任何錯誤當作事務中止錯誤,從而使其能夠被捕獲和處理。在 TRY 塊內,任何在顯式事務內出現的錯誤會使控制權傳遞給緊跟在 TRY 塊之後的 CATCH 塊。如果沒有錯誤出現,則跳過 CATCH 塊。如果想研究所發生錯誤的類型並相應地做出反應,必須將 @@error 的返回值保存到位於 CATCH 塊開始處的一個變量中,然後再開始研究。否則 @@error 返回的值可能不正確,因為除了 DECLARE 之外的任何語句都能夠更改它。
當事務中止錯誤發生在位於 TRY 塊裡的事務內且控制權傳遞給 CATCH 塊時,事務就進入了注定失敗的狀態。在您顯式地發出一個 ROLLBACK 命令之前,鎖是不會釋放的,已經持續存儲的工作也無法逆轉。在發出 ROLLBACK 之前,不允許啟動任何需要打開隱式或者顯式事務的操作。您可以檢查導致了錯誤的事務中已經更改的資源的內容,這樣可以看到什麼發生了更改,但是必須發出一個 ROLLBACK,以采取需要發生事務的補救措施。請注意,為了捕獲 CATCH 塊內出現的錯誤,必須在嵌套 TRY/CATCH 構造內編寫代碼。為了看一個更詳細的示例,我們首先創建一個 ErrorLog 表(其中錯誤處理代碼要對注釋進行審核),然後創建 T1 和 T2 表,對它們發出查詢,如我用圖 2 的代碼所完成的功能那樣。
接下來,在新的連接(稱為連接 1)中運行圖 3 中的腳本(稱為腳本 1)。腳本 1 將鎖的超時設定設置為 30 秒並將死鎖優先級設置為低,從那麼它在一個死鎖情況中自願成為一個按正常優先級運行的進程發生死鎖的犧牲品。TRY 塊中的代碼更新了 T1,等待 10 秒,然後從 T2 選擇。如果事務無錯誤地完成,將在 ErrorLog 表中插入一行,其中有一個注釋表明它成功完成。
CATCH 塊設計成捕獲主鍵沖突錯誤、鎖的超時設定到期和重試邏輯的死鎖錯誤。您可以通過更改賦給位於代碼開始處的變量 @retry 的值,重新設置所需的重試次數,現在這個值被設置為 2。
在第一次運行圖 3 中的代碼之後,查看 ErrorLog 的內容。請注意事務成功完成了。要測試是否發生主鍵沖突錯誤,打開一個新的連接(稱為連接 2)並運行以下代碼:
INSERT INTO T1 VALUES(3)
回到連接 1 並再次運行腳本 1。如果查看 ErrorLog 的內容,應該可以看到其中記錄了一個主鍵沖突錯誤。轉到連接 2 並通過運行以下命令刪除剛插入的行:
DELETE FROM T1 WHERE col1 = 3
要測試鎖的超時設定是否到期,在連接 2 中運行以下代碼:
BEGIN TRAN UPDATE T1 SET col1 = 1
回到連接 1 並再次運行腳本 1。在大約 30 秒後,應該出現一個錯誤。查看 ErrorLog 的內容,可以發現記錄了一條鎖的超時設定到期。轉到連接 2 並發出一條 ROLLBACK 命令以回滾事務。
為了測試是否存在死鎖,到連接 2 並粘貼以下代碼,但是暫時不運行:
DECLARE @i AS INT BEGIN TRAN SET @i = 1 WHILE @i <= 2 BEGIN UPDATE T2 SET col1 = 2 WAITFOR DELAY '00:00:10' SELECT * FROM T1 WAITFOR DELAY '00:00:05' SET @i = @i + 1 END ROLLBACK
轉到連接 1,運行腳本 1 中的代碼,然後立即運行連接 2 中的代碼。大約一分鐘之後,您將看到連接 1 中出現錯誤。查看 ErrorLog 的內容可以注意到在死鎖錯誤之後進行了兩次重試嘗試,第三次嘗試成功了,沒有發生錯誤。查詢 ErrorLog 表並查看其內容。
最後,如果想要在 TRY 塊內引發您自己的事務中止錯誤,您可以使用 TRAN_ABORT 選項調用 RAISERROR 命令。
Yukon 引入了一種新的隔離級別,稱為 SNAPSHOT,它允許您使用以下這種模式:寫入程序不會阻礙讀取程序,而且為讀取程序提供了它們所請求數據的已提交版本。SQL Server Yukon 在 tempdb 中維護著一個鏈接列表,負責跟蹤行的更改並為讀取程序構造一個較舊的已提交的數據版本。這種隔離對於開放式鎖定而言是有用的,在開放式鎖定中 UPDATE 沖突並不常見。如果進程 1 檢索數據,稍後又試圖對它進行修改,如果進程 2 在進程 1 檢索和修改之間也修改了同一數據,那麼 SQL Server 就會因為出現沖突,在進程 1 試圖進行修改時生成一個錯誤。然後,進程 1 可以嘗試重新發出事務。這種模式在更新沖突不太常見的情況下會非常高效。
為了能夠工作在 SNAPSHOT 隔離級別模式下,必須打開數據庫選項 ALLOW_SNAPSHOT_ISOLATION,稍後您就會看到這一點。為了模擬一個寫入程序不阻礙閱讀程序的情景,則創建一個 testdb 數據庫,打開相應的數據庫選項,並通過運行以下代碼,並創建一個在 datacol 列中具有值為“Version1”的 T1 表:
CREATE DATABASE testdb GO USE testdb ALTER DATABASE testdb SET ALLOW_SNAPSHOT_ISOLATION ON CREATE TABLE T1 ( keycol INT NOT NULL PRIMARY KEY, datacol VARCHAR(10) NOT NULL ) INSERT INTO T1 VALUES(1, 'Version1')
從連接 1 發出以下代碼,它將打開一個事務並將 datacol 中的值更改為“Version2”:
USE testdb BEGIN TRAN UPDATE T1 SET d
您正在看的SQLserver教程是:功能強大的全新 T-SQL 語法極大地提升了 SQL Server 的可編程性。atacol = 'Version2' WHERE keycol = 1 SELECT * FROM T1
轉到連接 2 並運行以下代碼,它將把會話的隔離級別設置為 SNAPSHOT,並檢索 T1 的內容:
USE testdb SET TRANSACTION ISOLATION LEVEL SNAPSHOT SELECT * FROM T1
請注意即使連接 2 將值改為“Version2”(但是還沒有提交更改),檢索回的還是“Version1”。
現在轉到連接 1 並提交事務,然後用一個 COMMIT 命令關閉所有連接。為了嘗試開放式鎖定,打開兩個新的連接,轉到連接 1 並運行以下代碼,它將把會話的隔離級別設置為 SNAPSHOT,打開一個事務,並從 T1 檢索數據:
SET TRANSACTION ISOLATION LEVEL SNAPSHOT BEGIN TRAN SELECT * FROM T1
轉到連接 2 並發出一條 UPDATE 命令:
UPDATE T1 SET datacol = 'Version3' WHERE keycol = 1
回到連接 1 並嘗試更新前面檢索到的同一數據。它已經被連接 2 修改了:
UPDATE T1 SET datacol = 'Version4' WHERE keycol = 1
將會獲得錯誤,通知您 SQL Server 不能使用快照隔離訪問數據庫 testdb 中的表 T1,而且您應該重試事務。
Yukon 中 WAITFOR 命令在許多方面進行了增強。除了等待指定的持續時間或者等待到某個 datetime 值,現在您還可以請求等待一條至少影響一行的 T-SQL 語句。可以指定命令等待以下語句之一:SELECT、INSERT、UPDATE、DELETE 或者 RECEIVE。前面的四個無需解釋了;RECEIVE 指的是從隊列中接收一條消息。如果希望在指定的毫秒數之後停止等待,可以選擇性地指定一個超時設定值。WAITFOR 命令的語法如下:
WAITFOR() [,TIMEOUT ]
Yukon 中另一個對 T-SQL 的功能增強允許您從數據操作語言 (DML) 的語句而不是 SELECT (INSER