SQL Server 事务提交超时

10

我在我的应用程序中遇到了一个奇怪的问题。它很少发生,可能每周一次或两次。基本上情况是这样的:

我在我的应用程序中有一个方法,它会多次查询数据库,首先有4个选择,其中一个使用关键字UPDLOCK,然后跟随另一个表(不是应用UPDLOCK的表)的插入和之前应用UPDLOCK的表的更新。

所有这些查询都在一个事务中完成(位于.NET的一侧),最后进行COMMIT操作。

现在,问题在于transaction.Commit()抛出异常,消息为:

超时已过期。在操作完成之前超时时间已过或服务器未响应。

(我猜测是因为SqlConnection超时了)。

所以我将整个过程包装在一个try-catch块中,如果出现异常,则尝试回滚事务,因此当发生这种情况时,代码执行转到catch块,并调用transaction.RollBack(),它也会抛出异常,消息为:

此SqlTransaction已完成。它不再可用。

(我猜测当COMMIT超时时,事务实际上已经COMMIT了),因此在这种情况下,应用程序的某些部分会出现问题。一些本来不存在的问题(因为ROLLBACK)实际上存在,并导致一些意外问题,这些问题随后需要手动修复。

除了增加SqlConnection的超时时间之外,我找不到任何可能指向问题所在的东西。如果有人以前遇到过这个问题,请分享一下经验,提前感谢。 (DB服务器的CPU利用率从未超过45-50%,在大多数情况下它处于3-15%的空闲状态)

这是第一个Sql Select --第一个选择

    SELECT TOP 1
            t.Id ,
            t.OId ,
            t.Amount ,
    t.DUserId,
            t.StartDate ,
            t.ExtDesc,
    t.StatusId
    FROM    dbo.[Transaction] t
            JOIN dbo.Wallet cw ON t.CId = cw.Id
            JOIN dbo.Wallet dw ON t.DId = dw.Id
    WHERE   ExtKey = @ExtKey 
            AND ( cw.vId = @vId 
                  OR dw.VId = @vId 
                )

--Second Selct which executes twice with differenc params


    SELECT  u.Id ,
            UserName ,
            PinCode ,
            CurrencyId ,
            StatusId ,
            PersonalNumber ,
            gu.DefaultVendorServiceId ,
            CountryId,
    u.FirstName,
    u.LastName
    FROM    dbo.[User] u
            LEFT JOIN dbo.GamblerUser gu ON gu.UserId = u.Id
    WHERE   u.Id = @UserId


--Last select with (updlock)


SELECT w.Id, AccountNo, FundTypeId, VendorServiceId, Balance, UserId, vs.IsLocalAccount

FROM Wallet w (UPDLOCK)
JOIN VendorService vs on w.VId = vs.Id
WHERE 
    w.UserId  = @UserId
AND w.FundTypeId = @FundTypeId 
AND w.VendorServiceId  = @VendorServiceId


-- Insert


    INSERT  INTO [dbo].[Transaction]
            ( StartDate ,
              OTypeId ,
              StatusId ,
              Amount ,
              ExtDesc,
              DUserId 
            )
    VALUES                  ( @StartDate ,
              @OTypeId ,
              @StatusId ,
              @Amount ,
              @ExtDesc,
              @DUserId 
            )

    SET @Id = ( SELECT  @@IDENTITY
              )


-- Update on updlocked table    


UPDATE dbo.Wallet SET

    Balance = ISNULL(@Balance, Balance)

WHERE Id = @Id
1个回答

11

(我假设这不是 Hekaton,因为 Hekaton 在提交方面有所不同。)

一个提交通常需要极少量的时间。必须将一次物理写入记录日志,并在镜像/AG的情况下进行网络往返。其中一件事可能会阻塞提交过程。

我个人曾经在超载的 Mirroring 连接中遇到过这个问题。

提交超时时间无法单独更改(我认为这是一个缺陷)。连接超时时间被使用。

请调查我上面提到的根本原因。可以通过增加提交超时时间来解决问题。

在提交失败的情况下,您不能假设事务实际上已提交或未提交。(这是“两个将军问题”,通常是无法解决的。)您必须设计某种检查方式,以确定数据库是否包含预期的写入操作。这在 Azure 上更为常见,可以查看 Azure 指南。


谢谢。网络出了一些问题(数据库已经镜像)。 - Dimitri

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接