SQL Server - 事务在出错时被锁定

时间:2017-05-24 21:19:05

标签: sql sql-server sql-server-2008 transactions locking

BEGIN TRANSACTION;
BEGIN TRY
    ALTER TABLE dbo.SomeLogs
    ADD SomeID NVARCHAR(250) NULL

    ALTER TABLE dbo.SomeLogs
    ADD SomeID NVARCHAR(250) NULL
    COMMIT TRANSACTION;
END TRY
BEGIN CATCH 
    ROLLBACK TRANSACTION;
    DECLARE @Msg NVARCHAR(MAX);
    SELECT @Msg = ERROR_MESSAGE();
    RAISERROR('Error Occured: %s', 20, 101, @Msg) WITH LOG;
END CATCH;

运行上面的查询会出现以下错误,这是正确的,因为我尝试将同一列添加两次。

Msg 2705,Level 16,State 4,Line 6 每个表中的列名必须是唯一的。列名称' SomeID'在表格中,dbo.SomeLogs'被指定不止一次。

但问题是SomeLogs表被锁定了。当我尝试在SomeLogs上执行SELECT时,我收到此错误。

无法检索此请求的数据。 (Microsoft.SqlServer.Management.Sdk.Sfc)

如需帮助,请点击:http://go.microsoft.com/fwlink?ProdName=Microsoft%20SQL%20Server&LinkId=20476

其他信息:

超出锁定请求超时时间。 (Microsoft SQL Server,错误:1222)

如需帮助,请点击:http://go.microsoft.com/fwlink?ProdName=Microsoft%20SQL%20Server&ProdVer=11.00.3000&EvtSrc=MSSQLServer&EvtID=1222&LinkId=20476

为什么catch块没有捕获此错误? 以及如何避免表被锁定?

3 个答案:

答案 0 :(得分:1)

使用TRY ... CATCH和XACT_STATE

https://docs.microsoft.com/en-us/sql/t-sql/language-elements/try-catch-transact-sql

  

以下示例显示了如何使用TRY ... CATCH构造   处理事务中发生的错误。 XACT_STATE函数   确定是应该提交还是回滚事务。   在此示例中,SET XACT_ABORT为ON。这使得交易成为可能   发生约束违规错误时无法提交。

答案 1 :(得分:1)

您可以指定SET XACT_ABORT ON在发生错误或注意时自动回滚事务(即客户端查询取消或超时)。我在SQL 2012及更高版本的存储过程和批处理中建议的一般TRY/CATCH模式:

SET XACT_ABORT ON;
BEGIN TRY
    BEGIN TRAN;
    --do stuff
    COMMIT;
END TRY
BEGIN CATCH 
    IF @@TRANCOUNT > 0 ROLLBACK TRANSACTION;
    THROW;
END CATCH;

有关详细说明,请参阅Erland Sommarskog's error handling article

答案 2 :(得分:1)

Try..Catch 

块不会捕获此错误,因为它的编译错误,并且无法在当前范围中捕获编译错误。 表保持锁定,因为在提交或回滚事务之前不会释放锁。当xact_abort设置为off(SSMS会话的默认值)时,在编译错误发生时,事务不会被回滚,即(坏!)设计,并且为了解决这个问题,你应该使用

set xact_abort on;

您可以在外部作用域中捕获此错误,例如,如果将此代码包装在存储过程或动态代码中,则在try..catch中执行sp / dynamic代码