我們可以把SSIS中的整個package包含在一個事務中,但是如果在package的執行過程中有一個表需要鎖定應該怎么處理呢?SSIS內建的事務處理可以解決這個問題。在此之前首先來熟悉一下SQL Server中的事務的概念。
事務
SQL Server中的事務是單個的工作單元。如果某一事務成功,則在該事務中進行的所有數據修改均會提交,成為數據庫中永久的組成部分。如果事務遇到錯誤且必須取消或回滾,則所有的數據修改均被清除。
在SQL Server中使用事務有可能會造成一些預想不到的結果,具體來說有臟讀,不可重復讀和幻讀三種結果。
在SQL Server中給事務指定一個隔離級別,這個隔離級別定義該事務與其他事務進行資源或數據更改相隔離的級別。事務隔離級別決定了是否鎖定SQL Server對象,下面是SQL Server中的事務隔離級別。
還有兩種是SQL Server 2005中新添加的事務隔離級別
所有上述的事務處理都在tempdb數據庫中一個類似版本庫的數據對象中自動進行,當遇到更新未被提交的情況,數據引擎會檢索這個版本庫得到合適的提交結果。維護這個版本庫的工作由SQL Server自動進行,不需要人為干預。
SSIS中的事務處理
SSIS中的包,容器(例如Loop,Foreach Loop,Sequence)或者一個單獨的任務中都可以設置事務處理選項。事務處理選項有下面一些值
內建的事務處理要使用Distributed Transaction Coordinator(MSDTC)服務,這個服務必須開啟。MSDTC允許使用分布式事務處理,例如在一個事務中同時處理SQL Server數據庫和Oracle數據庫。如果沒有開啟這個服務會得到下面的錯誤提示.
Error: 0xC001401A at Transaction: The SSIS Runtime has failed to start the distributed transaction due to error 0x8004D01B "The Transaction Manager is not available.". The DTC transaction failed to start. This could occur because the MSDTC Service is not running.
注意SSIS中包中的元素的事務隔離級別是Serializable,這種級別會影響鎖的持續時間。下面我們來用一個例子說明在如何package中鎖定一個表
1/*命名*/
2Create TranQueue Table
3/*SQLstatement設置*/
4IF NOT EXISTS ( SELECT * FROM sys.objects WHERE object_id =
5
6OBJECT_ID(N'dbo.TranQueue') AND type in (N'U') )
7BEGIN
8execute('CREATE TABLE dbo.TranQueue(message nvarchar(256))')
9END
10/*命名*/
11Populate TranQueue
12/*SQLstatement設置*/
13INSERT INTO dbo.TranQueue VALUES ('Test Message' + CONVERT
14
15(NVARCHAR(23), GETDATE(), 121))
16/*命名*/
17Create TranQueueHistory table
18/*SQLstatement設置*/
19IF NOT EXISTS ( SELECT * FROM sys.objects WHERE object_id =
20
21OBJECT_ID(N'dbo.TranQueueHistory') AND type in (N'U') )
22BEGIN
23execute('CREATE TABLE dbo.TranQueueHistory(message nvarchar(256))')
24END
1DELETE TOP(10) dbo.TranQueue
2OUTPUT DELETED.*
3INTO dbo.TranQueueHistory
4FROM dbo.TranQueue WITH (TABLOCKX)
圖1
10.打開SQL Server Management Studion,選擇對應的數據庫,新建一個Query,執行下面的語句,NOLOCK選項忽略鎖,這個語句查詢得到一條記錄 Message2011-04-10 14:22:31.043,但是這條記錄并沒有提交
1SELECT * FROM dbo.TranQueueHistory WITH (NOLOCK)
11.執行下面的語句
1SELECT * FROM dbo.TranQueue
語句將阻塞在這里,語句一直停留在執行狀態,不會結束。因為在Process TranQueue任務中我們使用TABLOCKX,在這里將等待任務回滾或者提交?;蛘呖梢詫懗蛇@樣,它任然會阻塞
1 DELETE TOP(10) dbo.TranQueue
2 INSERT INTO dbo.TranQueueHistory VALUES ('Test Message' + CONVERT(NVARCHAR(23), GETDATE(), 121))
12. 點擊Continue按鈕或者Debuge按鈕,會看到package執行失敗,執行SELECT * FROM dbo.TranQueueHistory
WITH (NOLOCK);因為執行了回滾,不會得到任何結果。SELECT * FROM dbo.TranQueue,任然有一條記錄。
SELECT * FROM dbo.TranQueueHistory WITH (NOLOCK)
NOLOCK提示忽略鎖,這個語句查詢得到一條記錄 Message2011-04-10 14:22:31.043,但是這條記錄并沒有提交
13. 執行下面的語句,
SELECT * FROM dbo.TranQueue
sql語句將阻塞在這里,語句一直執行。因為在Process TranQueue任務中我們使用TABLOCKX,在這里將等待任務回滾或者提交。或者可以寫成這樣
DELETE TOP(10) dbo.TranQueue;INSERT INTO dbo.TranQueueHistory VALUES ('Test Message' + CONVERT(NVARCHAR(23), GETDATE(), 121)),它任然會阻塞
14. 點擊Continue按鈕或者Debuge按鈕,會看到package執行失敗,執行SELECT * FROM dbo.TranQueueHistory WITH (NOLOCK);因為執行了回滾,不會得到任何結果。執行SELECT * FROM dbo.TranQueue,任然有一條記錄。
如果設置變量User::v_SimulateFailure的值為0,不會執行Simulate Failure任務,就不會回滾,TranQueue中的記錄會被寫入到TranQueueHistory中。這里有一個很有意思的語句:
DELETE TOP(10) dbo.TranQueue
OUTPUT DELETED.*
INTO dbo.TranQueueHistory
FROM dbo.TranQueue WITH (TABLOCKX)
如果兩個表的結構有一部分是是一樣的,現在想把一個表的數據導入到另外一個表中,可以使用DELETE SourceTable OUTPUT DELETE.*/DELETE.Column1,DELETE.Column2... INTO DestinationTable FROM SourceTable,這樣第一個表中的數據會被“剪切”到第二個表中。
新聞熱點
疑難解答