Sql server 回滚事务不工作

Sql server 回滚事务不工作,sql-server,tsql,Sql Server,Tsql,我有两张桌子tblproduct和tblproduct SALES。 我想看看如何开始传输、回滚工作 存储过程中有一个insert语句和update语句。如果其中一条语句失败,则两条语句都应回滚。但即使Update语句失败,回滚也不起作用。有什么建议吗 CREATE PROCEDURE spbasam_ProductSales @ProductId int, @QtyNeeded int AS BEGIN --Check the if you have enough stock to see D

我有两张桌子tblproduct和tblproduct SALES。 我想看看如何开始传输、回滚工作

存储过程中有一个insert语句和update语句。如果其中一条语句失败,则两条语句都应回滚。但即使Update语句失败,回滚也不起作用。有什么建议吗

CREATE PROCEDURE spbasam_ProductSales
@ProductId int,
@QtyNeeded int
AS
BEGIN
--Check the if you have enough stock to see
DECLARE @productavailabiltycount int
SELECT @productavailabiltycount = QtyAvailable FROM dbo.tblProduct where ProductId = @ProductId

--check to see if you have enough

If (@productavailabiltycount < @QtyNeeded)

    BEGIN
        Raiserror('Not enough stock available',16,1)

    END
Else
    BEGIN
        BEGIN TRY   
            BEGIN TRAN
            --Step 1 to reduce tblProduct table
                DECLARE @toupdate int

                UPDATE dbo.tblProduct set QtyAvailable = @productavailabiltycount - @QtyNeeded
                       WHERE ProductId = @ProductId
            -- Step 2 insert into tblProductSales table
               --First get the max count of the productSalesId
               DECLARE @maxcountid int

               SELECT @maxcountid = MAX(ProductSalesId) from dbo.tblProductSales
               INSERT INTO dbo.tblProductSales Values(@maxcountid+1 , @ProductId, @QtyNeeded)

            COMMIT TRAN     
        END TRY
        BEGIN CATCH
            Rollback Transaction

            SELECT 
                ERROR_NUMBER() as ErrorNumber,
                ERROR_MESSAGE() as ErrorMessage,
                ERROR_PROCEDURE() as ErrorProcedure,
                ERROR_STATE() as ErrorState,
                ERROR_LINE() as ErrorLine

        END CATCH       
    END
 END

 Exec spbasam_ProductSales 1,10
如果更新因SQL错误而失败,则会引发错误,并跳转到catch块。但是,如果更新失败,因为SQL根本找不到要更新的记录,则不会引发错误,下一个代码将继续执行。因此,您应该在update语句之后添加一个检查以查看更新了多少行,如果没有更新任何内容,则会引发您自己的错误

...
UPDATE dbo.tblProduct set QtyAvailable = QtyAvailable - @QtyNeeded
WHERE ProductId = @ProductId and QtyAvailable >= @QtyNeeded

if @@rowcount = 0
  raiserror('Insufficient quantity available.',16,1)
...
如果没有更新记录,这将把执行踢到catch块

而且,根据@JacobH在原始帖子评论中的建议,最好不要让可用数量变为负值。因此,如果在where子句中添加一个额外的检查,可以避免变成负数,并且一个与另一个同时订购的用户将无法完成他们的订单,因为在处理他们的订单之前,数量将减少。抓好雅各布


实际上,您可以重写整个过程以消除变量@productavailabiltycount,因为您只需在事务内部检查它,并且只有在当前事务有足够数量可用时才更新记录。

您如何知道更新失败?如果不产生错误,则不会回滚事务。也许您应该在update语句之后添加此行:如果@rowcount=0 raiserror'update failed'16,1,然后它会将其踢到catch块,并且在update语句之后不会继续执行其余语句。希望还有一些检查来确保数量只能是非负的,除非您也有某种缺货处理。这里可能还有一些并发性问题。如果两个用户同时运行此操作,并且在第一次检查中都返回了1 QTYAVALIABLE的计数,然后在以后的事务中都减去一个值,那么现在您得到了-1。旁白:您在事务外部获得了QTYAVALIABLE的副本,然后在事务内部使用可能过时的值。如果另一个进程在您的操作之间改变了值,那么这将导致难以定位竞争条件。既然你不。。。设置QtyAvailable-=@QtyNeeded。。。在更新中。这至少会使用最新的值,即使不再满足if条件。另一个旁白是:通常要避免在@MaxCountId+1创建一个伪标识列。以及识别insert语句insert ProductSalesId、ProductId、QUOTITYWORTED values@OPTIMITICVALUE、@ProductId、@QTYNEED中的列;使维护更加可预测。如果表架构发生更改(例如,在现有列之间添加了一列),会发生什么情况?现在可以工作了。这很奇怪。我已经关闭了SQL server管理工作室,并重试了一次,它可以正常工作。