我有两个表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
答案 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
,因为你可以在事务中简单地检查它,并且只有在当前事务有足够数量的情况下才更新记录。