1. 程式人生 > >一個簡單的存儲過程使用事務的例子

一個簡單的存儲過程使用事務的例子

通過 sca 當前 cat 就是 orm nsca ack 簡單

一、存儲過程中使用事務的簡單語法

在存儲過程中使用事務時非常重要,使用數據庫可以保持數據的關聯完整性,在SQL Server存儲過程中使用事務也很簡單,舉個例子:

技術分享圖片
Create  Procedure MyProcedure
(
   @Param1 nvarchar(10),
   @Param2 nvarchar(10)
)
AS
    Begin  
              Set NOCUNT ON;
              Set XACT_ABORT on;
              Begin  Tran
                      Delete  from  table1 where name=‘abc‘;
                      insert   into   table2  values(value1,value2,value3);  
              Commit  Tran
    End
   
技術分享圖片

說明:1、使用存儲過程執行事務,需要開啟XACT_ABORT參數(默認值Off),將該參數設置On,表示當執行事務時,如果出錯,會將transcation設置為uncommittable狀態,那麽在語句塊批處理結束後;如果該參數設置為Off,表示當執行事務時,如果出錯,出錯的語句將不會執行,其他正確的操作繼續執行。

2、當Set Nocunt為ON時,不返回計數(計數表示受Transact-SQL語句影響的行數,例如在SQL Server查詢分析器中執行一個Delete操作後,下方窗口提示(3) Rows Affeted)。當Set NOCOUNT 為OFF時,返回計數,我們應該在存儲過程的頭部加上Set NOCOUNT ON這樣的話,在推出存儲過程的時候加上Set Nocunt Off這樣的話,以達到優化存儲過程的目的。

二、事務內設置保存點

用戶可以在事務內設置保存點或標記。保存點定義如果有條件地取消事務的一部分,事務可以返回的位置。如果將事務回滾到保存點,則必須(如果需要,使用更多的Transact-SQL語句和Commite Transaction語句)繼續完成事務,或者必須(通過事務回滾到起始點)完全取消事務。若要取消整個事務,請使用Rollback Tansaction_name格式。這將撤銷事務的所有語句和過程。如:

技術分享圖片
Create  Procedure  MyProcedure
AS
     Begin
             Set  NOCUNT  ON;
             Set   XACT_ABORT  ON;
             begin  tran  ok --開始一個事務OK 
                    delete  from  rxqz  where qz=rx015‘  --刪除數據
         save  tran  bcd  --保存一個事務點命名為bcd
                update  sz  set name=‘ln‘  where name=‘l‘  ----修改數據
         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語句來捕獲錯誤,如下:

技術分享圖片
 Create Procedure  MyProcedure   
 (  
@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_NUMBER() 返回錯誤號。

    ERROR_SEVERITY() 返回嚴重性。

    ERROR_STATE() 返回錯誤狀態號。

    ERROR_PROCEDURE() 返回出現錯誤的存儲過程或觸發器的名稱。

    ERROR_LINE() 返回導致錯誤的例程中的行號。

    ERROR_MESSAGE() 返回錯誤消息的完整文本。該文本可包括任何可替換參數所提供的值,如長度、對象名或時間。

    2、有些錯誤,如sql語句中的表名稱輸入錯誤,這是數據庫引擎無法解析這個表名稱時,所發生的錯誤在當前的try…catch語句中無法捕獲,必須由外層調用該存儲過程的地方使用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 on

技術分享圖片 技術分享圖片 技術分享圖片代碼 Create proc myProcedure
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

技術分享圖片 技術分享圖片 技術分享圖片代碼 Create proc myProcedure
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 技術分享圖片 技術分享圖片

另外,對於@@Trancount需要說明的是,begin tran 語句將 @@Trancount加 1。Rollback tran將 @@Trancount遞減到 0,但 Rollback tran savepoint_name 除外,它不影響 @@Trancount。Commit tran 或 Commit work 將 @@Trancount 遞減 1。

一個簡單的存儲過程使用事務的例子