令人鬱悶的“事務中的變量賦值錯誤”

 

         事務中的變量(包括表變量)的操作是不受事務控制的。但是反過來,事務中的變量操作失敗,卻會導致事務提交失敗,這個有點讓人鬱悶。

         下面的腳本演示這個問題。示例演示分拆以逗號分隔的 @ids 中的每個 id 如果這個 id 是數字(int型),則做後面的處理;如果不是數字(賦值失敗,進入CATCH塊),則跳過這個id,處理下一個。整個處理在一個事務中進行。

DECLARE

    @ids varchar(1000);

SET @ids = '1,a,3,';

 

BEGIN TRY

    BEGIN TRAN;

   

    -- 循環分拆@ids 中以逗號分隔的每個id

    WHILE CHARINDEX(',', @ids) > 0

    BEGIN

       DECLARE

           @id int;

      

       BEGIN TRY

           -- 獲取當前的id

           SET @id =LEFT(@ids, CHARINDEX(',', @ids) - 1);

       END TRY

       BEGIN CATCH

           -- @ids 中去掉當前的id

           SET @ids = STUFF(@ids, 1, CHARINDEX(',', @ids), '');

           CONTINUE;

       END CATCH

       -- @ids 中去掉當前的id

       SET @ids = STUFF(@ids, 1, CHARINDEX(',', @ids), '');

 

       -- 處理id

       RAISERROR('current id: %d', 10, 1, @id) WITH NOWAIT;

    END

   

    COMMIT TRAN;

END TRY

BEGIN CATCH

    IF XACT_STATE() <> 0

       ROLLBACK TRAN;

   

    SELECT

       err_line = ERROR_LINE(),

       err_message = ERROR_MESSAGE();

END CATCH

 

         這個腳本執行後,輸出消息如下:

current id: 1

current id: 3

   err_line err_message

----------- -------------------------------------------------------

         30 當前事務無法提交,而且無法支持寫入日誌文件的操作。請回滾該事務。

 

(1 行受影響)

 

這個結果表明,@ids 中的所有 id 確實在循環中處理過,但第二個id由於不是數字,所以跳過了。但最終提交事務失敗了,因爲第二個id不是數字,導致賦值失敗,從而導致事務不可提交。

發現這個問題是因爲公司在用Service Broker傳遞業務數據,由於傳遞的xml數據有問題,導致類型不是期望有類型,從而使處理失敗。

個人覺得這個問題有點令人討厭,按照我的理解,既然不受事務控制,那麼它也不應該反過來影響事務,可是結果與理解的不一樣,值得注意。

最後補充一下:寫這個的重點在於提醒大家,在事務處理中,不要忽略那些看起來與事務無關的處理,它們出錯一樣會影響事務的最終提交。當然,解決的辦法是把這與事務無關的操作放在事務外(不過如果是存儲過程嵌套,就不好控制)。另外一個,只要處理可能會在事務中,則出錯時都拋出錯誤,而不試圖忽略錯誤,這樣可以解決問題。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章