一、存儲過程中使用事務的簡單語法
( @Param1 nvarchar( 10 ),
@param2 nvarchar( 10 )
)
AS
Begin
Set NOCOUNT ON;
Set XACT_ABORT ON;
Begin Tran
Delete from table1 where name = ’abc’;
Insert into table2 values(value1,value2,value3);
Commit Tran
End
2、當SET NOCOUNT 為 ON 時,不返回計數(計數表示受 Transact-SQL 語句影響的行數,例如在Sql server查詢分析器中執行一個delete操作后,下方窗口會提示(3)Rows Affected)。當
二、事務內設置保存點
用戶可以在事務內設置保存點或標記。保存點定義如果有條件地取消事務的一部分,事務可以返回的位置。如果將事務回滾到保存點,則必須(如果需要,使用更多的 Transact-SQL 語句和 COMMIT TRANSACTION 語句)繼續完成事務,或者必須(通過將事務回滾到其起始點)完全取消事務。若要取消整個事務,請使用 ROLLBACK TRANSACTION transaction_name 格式。這將撤消事務的所有語句和過程。如:
AS
Begin
Set NOCOUNT ON;
Set XACT_ABORT ON;
begin tran ok -- 開始一個事務OK
delete from rxqz where qz = ' rx015 ' -- 刪除數據
save tran bcd -- 保存一個事務點命名為bcd
update sz set name = ' 李麗s ' where name = ' 李麗 ' -- 修改數據
if @@error <> 0 -- 判斷修改數據有沒有出錯
begin -- 如果出錯
rollback tran bcd -- 回滾事務到BCD 的還原點
commit tran ok -- 提交事務
end
else -- 沒有出錯
commit tran ok -- 提交事務
End
說明:1、@@error判斷是否有錯誤,為0表示沒有錯誤,但是對那種重大錯誤無法捕捉,而且@@error只能前一句sql語句生效。
三、存儲過程使用try…catch捕獲錯誤
在存儲過程中可以使用try…catch語句來捕獲錯誤,如下:
( @Param1 nvarchar( 10 ),
@param2 nvarchar( 10 )
)
AS
Begin
Set NOCOUNT ON;
Begin try
Delete from table1 where name = ’abc’;
Insert into table2 values(value1,value2,value3);
End try
Begin Catch
SELECT ERROR_NUMBER() AS ErrorNumber,
ERROR_MESSAGE() AS ErrorMessage;
End Catch
End
說明:1、捕獲錯誤的函數有很多,如下:
ERROR_SEVERITY() 返回嚴重性。
ERROR_STATE() 返回錯誤狀態號。
ERROR_PROCEDURE() 返回出現錯誤的存儲過程或觸發器的名稱。
ERROR_LINE() 返回導致錯誤的例程中的行號。
ERROR_MESSAGE() 返回錯誤消息的完整文本。該文本可包括任何可替換參數所提供的值,如長度、對象名或時間。
2、有些錯誤,如sql語句中的表名稱輸入錯誤,這是數據庫引擎無法解析這個表名稱時,所發生的錯誤在當前的try…catch語句中無法捕獲,必須由外層調用該存儲過程的地方使用
四、存儲過程中事務和try…catch聯合使用
在存儲過程中使用事務時,如果沒有try…catch語句,那么當set xact_abort on時,如果有錯誤發生,在批處理語句結束后,系統會自動回滾所有的sql操作。當set xact_abort off時,如果有錯誤發生,在批處理語句結束后,系統會執行所有沒有發生錯誤的語句,發生錯誤的語句將不會被執行。
在存儲過程中使用事務時,如果存在try…catch語句塊,那么當捕獲到錯誤時,需要在catch語句塊中手動進行Rollback操作,否則系統會給客戶端傳遞一條錯誤信息。如果在存儲過程開始處將set xact_abort on,那么當有錯誤發生時,系統會將當前事務置為不可提交狀態,即會將xact_state()置為-1,此時只可以對事務進行Rollback操作,不可進行提交(commit)操作,那么我們在catch語句塊中就可以根據xact_state()的值來判斷是否有事務處於不可提交狀態,如果有則可以進行rollback操作了。如果在存儲過程開始處將set xact_abort off,那么當有錯誤發生時,系統不會講xact_state()置為-1,那么我們在catch塊中就不可以根據該函數值來判斷是否需要進行 rollback了,但是我們可以根據@@Trancount全局變量來判斷,如果在catch塊中判斷出@@Trancount數值大於0,代表還有未提交的事務,既然進入catch語句塊了,那么還存在未提交的事務,該事務應該是需要rollback的,但是這種方法在某些情況下可能判斷的不准確。推薦的方法還是將set xact_abort on,然后在catch中判斷xact_state()的值來判斷是否需要Rollback操作。
下面我們來看看兩個例子:
一.使用Set xact_abort
代碼
As
begin
set xact_abort on;
begin try
begin tran
insert into TestStu values( ' Terry ' , ' boy ' , 23 );
insert into TestStu values( ' Mary ' , ' girl ' , 21 );
commit tran
end try
begin catch
-- 在此可以使用xact_state()來判斷是否有不可提交的事務,不可提交的事務
-- 表示在事務內部發生錯誤了。Xact_state()有三種值: - 1 .事務不可提交;
-- 1 .事務可提交; 0 .表示沒有事務,此時commit或者rollback會報錯。
if xact_state() =- 1
rollback tran;
end catch
end
二.使用Set xact_abort off
As
begin
set xact_abort off;
begin try
begin tran
insert into TestStu values( ' Terry ' , ' boy ' , 23 );
insert into TestStu values( ' Mary ' , ' girl ' , 21 );
commit tran
end try
begin catch
-- 在此不可以使用xact_state來判斷是否有不可提交的事務
-- 只可以使用@@Trancount來判斷是否有還未提交的事務,未提交的事務未必
-- 就是不可提交的事務,所以使用@@TranCount > 0后就RollBack是不准確的
if @@TranCount > 0
rollback tran;
end catch
end