回滚事务无法正常工作

时间:2018-02-06 20:11:34

标签: sql-server tsql

2 tables with data image

我有两个表tblproduct和tblproductsales。 我想看看Begin Tran,Rollback是如何工作的。

存储过程中有一个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

1 个答案:

答案 0 :(得分:0)

如果update因SQL错误而失败,则会引发错误并跳转到catch块。但是,如果update失败,因为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,因为你可以在事务中简单地检查它,并且只有在当前事务有足够数量的情况下才更新记录。