1. 程式人生 > >你真的瞭解事務嗎?

你真的瞭解事務嗎?

事務用於處理資料的一致性,事務的定義是,處於同一個事務中的操作是一個工作單元,要麼全部執行成功,要麼全部執行失敗。把事務的概念應用到在實際的SSIS Package場景中,如何在Package中實現事務,事務的行為是什麼樣的,你真的瞭解嗎?

SSIS預設支援Task元件級別的事務,在預設情況下,單個Task元件在開始執行時,會開啟連線,開啟一個事務,等到Task元件執行完成,提交事務,關閉連線,也就是說,預設情況下,單個Task元件在單個事務中執行查詢,因此,在單個Execute SQL Task元件中執行大量的TSQL指令碼,不是明智的選擇,因為,這會導致日誌檔案的激增。如果Task元件執行失敗,SSIS引擎自動進行回滾Task級別上的事務。如果在Task中使用begin tran命令開啟一個顯式事務,必須在元件中顯式提交事務;當執行顯式事務的元件失敗時,元件會回滾顯式事務。SSIS支援更復雜的事務處理,包括單一連線的本機事務,和跨連線的分散式事務處理。

一,SSIS支援的事務

在SSIS Package中,按照事務的分佈性,可以把事務分為兩種型別:

  • 分散式事務:通過分散式事務協調器(DTC,Distributed Transaction Coordinator) 實現跨連線,Task和Package的事務處理;
  • 本機事務:是SQL Server引擎級別事務,通過TSQL事務命令管理的單一連線的事務處理;

事務處理,都依賴連線管理器的支援。讓Package使用本機事務的關鍵是所有的任務元件都使用相同的連線管理器,並且連線管理器(Connection Manager)上的屬性RetainSameConnection設定為True:

讓Package使用分散式事務的關鍵是所有的任務元件使用的連線管理器都支援DTC事務,並且連線管理器的SupportsDTCTransactions

屬性值都為True:

二,單個Task元件的事務處理

最常用的Task元件是Execute SQL Task元件,在該元件中執行的TSQL指令碼處於同一個事務中。在該Task元件執行時,開啟連線,開啟一個事務,直到所有的TSQL指令碼都成功執行,元件執行成功;一旦該Task中的某個TSQL指令碼執行失敗,事務回滾,這意味著,該Task中的所有已經執行的TSQL指令碼都將回滾。因此,在單個Execute SQL Task元件中執行大量的TSQL指令碼,不是明智的選擇,因為,這會導致日誌檔案的激增。

建立測試表,測試表只有一列:

create table dbo.dt_test
(ID int
)

在Execute SQL Task元件中執行以下語句:

insert into dbo.dt_test
values(1)

insert into dbo.dt_test
values('a')

Task元件執行失敗,從資料庫中檢視,測試表中沒有插入任何資料,這說明,單個Task中的所有TSQL語句都包含在單個事務中。

三,本機事務處理(多Task元件,單一連線,單一事務)

在SSIS的任務和容器元件中,很多操作都需要連線到資料庫執行查詢,使用本機事務處理的關鍵是,所有的任務元件都使用相同的連線管理器,並且設定連線管理的屬性RetainSameConnection為True,其預設值是False。

如果連線管理器的屬性RetainSameConnection值是False,那麼每個Task元件在開始執行時,開啟連線,在元件結束時,關閉連線。在元件執行結束時,如果存在未提交的事務,那麼元件會自動回滾Task元件的TSQL查詢語句。由於每個元件都會開啟和關閉連線,即使兩個元件,使用的是同一個連線管理器,它們使用的連線都是不同的。

  • 案例1:有兩個元件,在一個元件中建立一個臨時表或臨時變數,在另一個元件中是不能使用的,這是因為在第一個元件結束時,連線也被關閉,臨時表或臨時變數的生命週期結束。
  • 案例2:在迴圈任務中連線資料庫時,設定RetainSameConnection值是True,能夠避免頻繁地開啟/關閉連線。在Package開始執行時,開啟連線,package結束時,關閉連線,保證所有task元件使用的都是同一個連線。

如果連線管理器的屬性RetainSameConnection值是true,那麼連線管理器會保持開啟,直到Package結束,連線才會關閉。在連線關閉時,SSIS引擎會檢查連線中是否存在未提交的事務,如果存在,執行事務回滾。

  • 案例3:有兩個元件,使用的是同一個連線管理器,屬性RetainSameConnection值是true。在一個元件中建立一個臨時表或臨時變數,在另一個元件中可以使用,這是因為在第一個元件結束時,連線沒有被關閉,兩個元件使用的是同一個連線,臨時表或臨時變數的生命週期會持續到Package結束。
  • 案例4:將連線管理器的屬性RetainSameConnection設定為true,在上游元件中開啟事務,在下游元件中提交事務,實現本機事務處理。

示例,利用TSQL命令(begin/commit/rollback tran)實現事務的提交或回滾

Package的設計如下圖所示:

Exec TSQL元件執行的TSQL語句是:dbo.dt_test只有一列 ID,是int型別,該元件會執行失敗。

insert into dbo.dt_test
values('a')

case1,設定連線管理器的RetainSameConnection屬性值為False,rollback tran元件執行報錯

從Progess選項卡中,檢視Exec TSQL元件丟擲的錯誤訊息是:

insert into dbo..." failed with the following error: "Conversion failed when converting the varchar value 'a' to data type int.".

rollback tran 元件丟擲的錯誤訊息是:

[Execute SQL Task] Error: Executing the query "rollback tran" failed with the following error: "The ROLLBACK TRANSACTION request has no corresponding BEGIN TRANSACTION.". 

分析:由於連線管理器的屬性RetainSameConnection為False,每個Task元件都是單獨開啟和關閉連線,begin tran元件已經把顯式事務提交,rollback tran元件沒有begin tran子句,無法執行事務回滾。

case2,設定連線管理器的RetainSameConnection屬性值為True

1,設定連線管理器的RetainSameConnection屬性值為True,rollback tran元件執行報錯

把連線管理器的屬性RetainSameConnection設定為True,使所有的Task元件使用的連線都是相同的。再次執行Package,還是失敗,錯誤原因是:

[Execute SQL Task] Error: Executing the query "rollback tran" failed with the following error: "The ROLLBACK TRANSACTION request has no corresponding BEGIN TRANSACTION.".

這是由於Execute SQL Task 在失敗時,SSIS引擎自動進行事務的回滾。

這個結論可以通過增加一個Insert 1 元件來實現,向測試表中插入數值1,程式碼如下:

insert into dbo.dt_test
values(1)

在Exec TSQL元件上新增OnPostExecute斷點,在Task執行之後,丟擲錯誤之前,停止程式的執行:

重新執行Package,在執行到斷點時,測試表已經插入的數值1 被刪除,這說明,Exec TSQL元件的失敗,會導致整個事務自動回滾。

結論1:當Execute SQL Task執行失敗時,SSIS自動進行事務的回滾,但是當Execute SQL Task執行成功時,不會自動提交顯式事務;開啟一個顯式事務,必須顯式提交事務。

2,開啟一個顯式事務,需要顯式提交事務

把Exec TSQL執行的語句修改插入數值2,這樣,元件執行成功:

insert into dbo.dt_test
values(2)

如果把commit tran元件禁用,Package執行成功,但是測試表中沒有插入任何資料,這說明,Package執行完成之後,連線管理器檢測到有未提交的事務,自動把未提交的事務回滾。下圖所示,事務並沒有提交成功,而是被回滾。

結論2:開啟一個顯式事務,需要顯式提交事務。當連線關閉時,SSIS會回滾未提交的顯式事務。SSIS會檢查每一個連線內是否存在未提交的顯式事務,如果存在,那麼回滾該事務;對於隱式事務,當TSQL語句執行結束時,會自動提交或回滾。

四,分散式事務處理(多Task元件,多連線,單一事務)

本機事務只能使用單一連線,在同一個連線中通過TSQL命令執行事務處理,不能實現跨連線,不能跨資料庫的事務,由於SSIS經常需要處理多個數據庫的資料,本機事務無法實現跨資料庫的事務處理,使用者可以通過MS DTC(微軟分散式事務服務)實現分散式事務處理。

在SSIS 引擎伺服器上啟用MS DTC服務,並在Package的Task元件上設定相應的TransactionOption,就能使用分散式事務。

每個可執行元件(Task或Container)都包含Transactions屬性組,SSIS通過這兩個屬性實現事務處理:

  • IsoLationLevel:設定事務的隔離級別;
  • TransactionOption:設定事務選項;
    • Supported:如果已經存在一個事務,那麼當前元件加入到事務中;
    • Not Supported:即使存在一個事務,當前元件也不會加入到事務中;
    • Requried:如果存在事務,那麼當前元件加入到事務中;如果不存在事務,那麼啟動一個事務。

案例:兩個Task,一個事務

在單一Package的不同Task元件中引用分散式事務,簡化的設計如下圖,兩個Task元件使用不同的連線管理器:

設定Required元件的TransactionOption屬性為Required,開啟一個分散式事務處理:

設定Supported元件的TransactionOption屬性為Supported,加入到當前的事務中,這就意味著,一個事務就包含兩個Task,兩個連線:

這樣設定之後,在同一個Package的不同的Task元件中,一個跨連線的分散式事務處理建立完成。

分散式事務處理,還支援多Package,多連線,單一事務模式,不再贅述。