拥有存储过程并以
格式包装代码BEGIN TRY
BEGIN TRAN
...code
COMMIT
END TRY
BEGIN CATCH
ROLLBACK
...code
END CATCH
在我开始对各种错误进行一些测试以确保它们正确地输入我的日志表之前,哪个工作正常。
但是,当我运行它时,它会失败,并且不会回滚并需要手动回滚。这就像代码没有意识到它处于TRY块中。
有什么想法吗? (下面的代码,希望它可以在其他人的系统上重新创建,而不是如何配置我所在系统的奇怪方式)
BEGIN
SET NOCOUNT ON
BEGIN TRY
BEGIN TRAN
---------------------------------------------------------------------
-- Create test table
---------------------------------------------------------------------
IF OBJECT_ID('tempdb..#DateOfBirth') IS NOT NULL DROP TABLE #DateOfBirth
CREATE TABLE #DateOfBirth
(
DateOfBirth DATE
)
INSERT INTO #DateOfBirth
VALUES
('1984-12-09')
,('1977-12-09')
,('2015-03-12')
,('1967-01-15')
---------------------------------------------------------------------
-- Date Of Birth
-- This Insert errors
---------------------------------------------------------------------
IF OBJECT_ID('tempdb..#DOB') IS NOT NULL DROP TABLE #DOB
CREATE TABLE #DOB
(
groupID INT IDENTITY(1,1)
, DateOfBirth INT -- Data Type mismatch
)
INSERT INTO #DOB
SELECT DateOfBirth
FROM #DateOfBirth
COMMIT
END TRY
BEGIN CATCH
PRINT 'Rollback'
ROLLBACK
DECLARE @ErrorMessage NVARCHAR(4000) = ERROR_MESSAGE(),
@ErrorState INT = ERROR_STATE(),
@ErrorSeverity INT = ERROR_SEVERITY();
RAISERROR(@ErrorMessage, @ErrorSeverity, @ErrorState);
END CATCH
END
GO
答案 0 :(得分:2)
无法捕获CATCH块相同范围内的编译错误。也就是说,在每个语句之前添加一个PRINT:
PRINT 'BATCH STARTED';
BEGIN
SET NOCOUNT ON
BEGIN TRY
PRINT 'BEGIN TRAN';
BEGIN TRAN;
IF OBJECT_ID('tempdb..#DateOfBirth') IS NOT NULL DROP TABLE #DateOfBirth;
PRINT 'CREATING #DateOfBirth';
CREATE TABLE #DateOfBirth
(
DateOfBirth DATE
);
PRINT 'INSERTING INTO #DateOfBirth';
INSERT INTO #DateOfBirth
VALUES
('1984-12-09')
,('1977-12-09')
,('2015-03-12')
,('1967-01-15')
IF OBJECT_ID('tempdb..#DOB') IS NOT NULL DROP TABLE #DOB;
PRINT 'CREATING #DOB';
CREATE TABLE #DOB
(
groupID INT IDENTITY(1,1)
, DateOfBirth INT -- Data Type mismatch
);
PRINT 'INSERTING INTO #DOB';
INSERT INTO #DOB
SELECT DateOfBirth
FROM #DateOfBirth;
PRINT 'COMMIT';
COMMIT;
END TRY
BEGIN CATCH
PRINT 'ROLLBACK';
ROLLBACK;
DECLARE @ErrorMessage NVARCHAR(4000) = ERROR_MESSAGE(),
@ErrorState INT = ERROR_STATE(),
@ErrorSeverity INT = ERROR_SEVERITY();
RAISERROR(@ErrorMessage, @ErrorSeverity, @ErrorState);
END CATCH;
END;
GO
当最初在新会话上执行此批处理时,生成的消息为:
BATCH STARTED
BEGIN TRAN
CREATING #DateOfBirth
INSERTING INTO #DateOfBirth
CREATING #DOB
INSERTING INTO #DOB
Msg 206, Level 16, State 2, Line 36
Operand type clash: date is incompatible with int
重要的一点是,在语句编译期间发生此错误,而不是执行。因为在编译批处理时临时表不存在,所以引用这些表的语句的编译将推迟到语句运行之前。编译期间发生的任何错误都不能被同一范围内的CATCH块捕获。
如果使用动态SQL执行语句,则可以捕获编译错误,以便编译在不同的范围内进行:
PRINT 'BATCH STARTED';
BEGIN
SET NOCOUNT ON
BEGIN TRY
PRINT 'BEGIN TRAN';
BEGIN TRAN;
EXECUTE('
IF OBJECT_ID(''tempdb..#DateOfBirth'') IS NOT NULL DROP TABLE #DateOfBirth;
PRINT ''CREATING #DateOfBirth'';
CREATE TABLE #DateOfBirth
(
DateOfBirth DATE
);
PRINT ''INSERTING INTO #DateOfBirth'';
INSERT INTO #DateOfBirth
VALUES
(''1984-12-09'')
,(''1977-12-09'')
,(''2015-03-12'')
,(''1967-01-15'')
IF OBJECT_ID(''tempdb..#DOB'') IS NOT NULL DROP TABLE #DOB;
PRINT ''CREATING #DOB'';
CREATE TABLE #DOB
(
groupID INT IDENTITY(1,1)
, DateOfBirth INT -- Data Type mismatch
);
PRINT ''INSERTING INTO #DOB'';
INSERT INTO #DOB
SELECT DateOfBirth
FROM #DateOfBirth;
PRINT ''COMMIT'';
COMMIT;
');
END TRY
BEGIN CATCH
PRINT 'ROLLBACK';
ROLLBACK;
DECLARE @ErrorMessage NVARCHAR(4000) = ERROR_MESSAGE(),
@ErrorState INT = ERROR_STATE(),
@ErrorSeverity INT = ERROR_SEVERITY();
RAISERROR(@ErrorMessage, @ErrorSeverity, @ErrorState);
END CATCH;
END;
GO
在这种情况下,输入CATCH块并回滚事务:
BATCH STARTED
BEGIN TRAN
CREATING #DateOfBirth
INSERTING INTO #DateOfBirth
CREATING #DOB
INSERTING INTO #DOB
ROLLBACK
Msg 50000, Level 16, State 2, Line 58
Operand type clash: date is incompatible with int
顺便说一下,我强烈建议您指定' SET XACT_ABORT ON'帮助确保在未执行CATCH块的情况下发生错误后回滚事务(例如客户端查询超时错误)。
答案 1 :(得分:1)
您遇到的错误是:
Msg 206, Level 16, State 2, Line 39
Operand type clash: date is incompatible with int
对于这种类型的错误,建议在应用程序范围内处理,因为批处理被简单地中止。
我编写了一些资源:
希望这会对你有所帮助。