Try / Catch不适用于T-SQL存储过程(不是回滚事务)

时间:2014-09-01 08:16:25

标签: sql-server tsql stored-procedures transactions try-catch

我有这个存储过程:

CREATE PROCEDURE [dbo].[MYSTOREDPROCEDURENAME]
AS
BEGIN   

BEGIN TRANSACTION;

BEGIN TRY

    CREATE TABLE [dbo].[#Temp](
        Col1 varchar(50) NOT NULL,
        Col2 varchar(50) NOT NULL,
        Col3 varchar(50) NOT NULL,
        Col4 smallint NULL)

    INSERT INTO [dbo].[#Temp]([Col1], [Col2], [Col3], [Col4])
    SELECT [Col1],[Col2],[Col3],[Col4] FROM [dbo].[MyTable]

    TRUNCATE TABLE [dbo].[MyTable]

    INSERT INTO [dbo].[MyTable] ( Col1, Col2, Col3, Col4 )
    SELECT Field1, Field2, Field3, ISNULL((SELECT Col4 FROM [dbo].[#Temp] WHERE [dbo].[#Temp].[Col1]=MyTable2.Field1 AND [dbo].[#Temp].[Col2]=MyTable2.Field2 AND [dbo].[#Temp].[Col3]=MyTable2.Field3),1) AS Espr1
    FROM [dbo].[MyTable2]

    DROP TABLE [dbo].[#Temp]
END TRY
BEGIN CATCH
    SELECT ERROR_NUMBER() AS ErrorNumber
          ,ERROR_SEVERITY() AS ErrorSeverity
          ,ERROR_STATE() AS ErrorState
          ,ERROR_PROCEDURE() AS ErrorProcedure
          ,ERROR_LINE() AS ErrorLine
          ,ERROR_MESSAGE() AS ErrorMessage;

    IF @@TRANCOUNT > 0
        ROLLBACK TRANSACTION;
END CATCH;

IF @@TRANCOUNT > 0
    COMMIT TRANSACTION;
END

如果我执行此sp,则会显示以下错误消息:

Msg 468,Level 16,State 9,Procedure MYSTOREDPROCEDCEDURENAME,Line 32 无法解决" Latin1_General_CI_AS"之间的整理冲突和" SQL_Latin1_General_CP1_CI_AS"在等于操作。 Msg 266,Level 16,State 2,Procedure MYSTOREDPROCEDCENURAME,32行 EXECUTE之后的事务计数表示缺少COMMIT或ROLLBACK TRANSACTION语句。先前的计数= 0,当前计数= 1.

现在,除了错误之外,我不明白为什么阻止"赶上"没有达到,事务回滚没有完成(错误" MyTable"被锁定!)

我哪里错了?为什么"赶上"块不起作用?

P.S。存储过程在Sql Server 2005上执行

2 个答案:

答案 0 :(得分:1)

我不知道为什么,但是try / catch仅适用于在try部分之外开始的事务。因此,您可以将begincommit移动到try部分,catch部分仍然会有rollback

此外,try / catch不会捕获一些错误,例如延迟名称解析错误。这是设计的。

UPD:啊,我明白了。这是答案:Issues with T-SQL TRY CATCH?

如图所示,SQL Server认为整理冲突与延迟名称解析失败一样严重。这个特定的错误不能被它发生的同一个模块中的try / catch捕获。

P.S。我最后一次遇到这个错误是在MSSQL 2000上,其中还没有引入try / catch,所以我不知道它没有被处理。对不起误导。

答案 1 :(得分:0)

您尝试阻止的原因是因为在执行任何代码之前很久就会对其进行解析和验证。这失败,所以什么都没有执行。

您的代码中有2个错误阻止它永远运行,第一个是排序错误。你应该更仔细地研究一下如何在1个数据库中发生这种情况并修复根本原因,但是现在你可以在违规列上使用COLLATE Latin1_General_CI_AS。

第二个错误正是Ennor所说的,你周围的交易尝试/捕获。这不是这个工作原理。例如,您可以完全删除BEGIN / COMMIT,因为他们无论如何都不会做任何事情。

这是一个功能齐全的示例,我刚刚在一个通用的sql server数据库中运行,默认选项名为[demo]。

use demo
go

create table [MyTable] (
    Col1 varchar(50) not null
    , Col2 varchar(50) not null
    , Col3 varchar(50) not null
    , Col4 smallint null
    )

insert MyTable
values (
    'some string'
    , 'some string'
    , 'some string'
    , 1
    )

create table [MyTable2] (
    Col1 varchar(50) not null
    , Col2 varchar(50) not null
    , Col3 varchar(50) not null
    , Col4 smallint null
    )
go

create procedure [dbo].[my_proc]
as
begin
begin try
begin transaction
    create table #Temp (
        Col1 varchar(50) not null
        , Col2 varchar(50) not null
        , Col3 varchar(50) not null
        , Col4 smallint null
        )

    insert into #Temp (
        [Col1]
        , [Col2]
        , [Col3]
        , [Col4]
        )
    select [Col1]
        , [Col2]
        , [Col3]
        , [Col4]
    from [dbo].[MyTable]

    truncate table [dbo].[MyTable]

    insert into [dbo].[MyTable] (
        Col1
        , Col2
        , Col3
        , Col4
        )
    select [Col1]
        , [Col2]
        , [Col3]
        , ISNULL((
                select Col4
                from #Temp
                where #Temp.[Col1] = MyTable2.[Col1]
                    and #Temp.[Col2] = MyTable2.[Col2]
                    and #Temp.[Col3] = MyTable2.[Col3]
                ), 1) as Espr1
    from [dbo].[MyTable2]

    drop table #Temp
    if @@TRANCOUNT <> 0
    commit transaction
end try

    begin catch
        select ERROR_NUMBER() as ErrorNumber
            , ERROR_SEVERITY() as ErrorSeverity
            , ERROR_STATE() as ErrorState
            , ERROR_PROCEDURE() as ErrorProcedure
            , ERROR_LINE() as ErrorLine
            , ERROR_MESSAGE() as ErrorMessage;

        if @@TRANCOUNT > 0
            rollback transaction;
    end catch;
end

exec my_proc