sql-server - 事务逻辑和错误处理问题
问题描述
我正在关注遵循 ACID 概念的交易在线教程。我有这两张表:
-- Create Product table
CREATE TABLE Product
(
ProductId INT PRIMARY KEY,
Name VARCHAR(50),
Price INT,
Quantity INT
)
GO
-- Populate the Product Table with some test data
INSERT INTO Product VALUES(101, 'Laptop', 1234, 100)
INSERT INTO Product VALUES(102, 'Desktop', 3456, 150)
INSERT INTO Product VALUES(103, 'Tablet', 5678, 200)
INSERT INTO Product VALUES(104, 'Mobile', 7890, 250)
GO
-- Create ProductSales table
CREATE TABLE ProductSales
(
ProductSalesId INT PRIMARY KEY,
ProductId INT,
QuantitySold INT
)
GO
我已经创建了一个带有交易的存储过程,我在其中提供了 productId 和要销售的数量。
这是我的存储过程:
CREATE PROCEDURE spSellProduct
@ProductID INT,
@QuantityToSell INT
AS
BEGIN
-- First we need to Check the stock available for the product we want to sell
DECLARE @StockAvailable INT
SELECT @StockAvailable = Quantity
FROM Product
WHERE ProductId = @ProductId
-- We need to throw an error to the calling application
-- if the stock is less than the quantity we want to sell
IF(@StockAvailable< @QuantityToSell)
BEGIN
Raiserror('Enough Stock is not available',16,1)
END
-- If enough stock is available
ELSE
BEGIN
BEGIN TRY
-- We need to start the transaction
BEGIN TRANSACTION
-- First we need to reduce the quantity available
UPDATE Product SET
Quantity = (Quantity - @QuantityToSell)
WHERE ProductID = @ProductID
-- Calculate MAX ProductSalesId
DECLARE @MaxProductSalesId INT
SELECT @MaxProductSalesId = CASE
WHEN MAX(ProductSalesId) IS NULL THEN 0
ELSE MAX(ProductSalesId)
END
FROM ProductSales
-- Increment @MaxProductSalesId by 1, so we don't get a primary key violation
Set @MaxProductSalesId = @MaxProductSalesId + 1
-- We need to insert the quantity sold into the ProductSales table
INSERT INTO ProductSales(ProductSalesId, ProductId, QuantitySold)
VALUES(@MaxProductSalesId, @ProductId, @QuantityToSell)
COMMIT TRANSACTION
END TRY
BEGIN CATCH
ROLLBACK TRANSACTION
SELECT ERROR_NUMBER() as ErrorNumber,
ERROR_MESSAGE() as ErrorMessage,
ERROR_PROCEDURE() as ErrorProcedure,
ERROR_STATE() as ErrorState,
ERROR_SEVERITY() as ErrorSeverity,
ERROR_LINE() as ErrorLine
END CATCH
End
END
go
spSellProduct @ProductId=103, @QuantityToSell=300
我检查数量是否少于要出售的数量,然后我会产生错误。如果没有遇到错误,那么我开始交易。
然后我从产品表中扣除数量。之后,我在 productSales 表中增加 ProductSalesId 并插入带有 ProductId 和 QuantitySold 的新行。
如果发生任何错误,我会尝试在我的 catch 批处理中处理它们并回滚事务。
因此,在我的 ProductId 103 的产品表中,它有 200 个库存数量,我按以下方式执行存储过程:
spSellProduct @ProductId=103, @QuantityToSell=300
当@QuantityToSell 大于 Quantity 时,不会生成错误并且事务不会回滚。在这种情况下,ProductId 的数量是 200,而我尝试销售的数量是 300。
我在这里做错了什么?
解决方案
您应该将所有过程代码放在 try catch 中,并在其中放置事务。尝试使用以下代码。
CREATE PROCEDURE [dbo].[spSellProduct]
@ProductID INT,
@QuantityToSell INT
AS
BEGIN
BEGIN TRY
BEGIN TRANSACTION
-- First we need to Check the stock available for the product we want to sell
DECLARE @StockAvailable INT
SELECT @StockAvailable = Quantity
FROM Product
WHERE ProductId = @ProductId
-- We need to throw an error to the calling application
-- if the stock is less than the quantity we want to sell
IF(@StockAvailable< @QuantityToSell)
BEGIN
Raiserror('Enough Stock is not available',16,1)
END
-- If enough stock is available
ELSE
BEGIN
-- First we need to reduce the quantity available
UPDATE Product SET
Quantity = (Quantity - @QuantityToSell)
WHERE ProductID = @ProductID
-- Calculate MAX ProductSalesId
DECLARE @MaxProductSalesId INT
SELECT @MaxProductSalesId = CASE
WHEN MAX(ProductSalesId) IS NULL THEN 0
ELSE MAX(ProductSalesId)
END
FROM ProductSales
-- Increment @MaxProductSalesId by 1, so we don't get a primary key violation
Set @MaxProductSalesId = @MaxProductSalesId + 1
-- We need to insert the quantity sold into the ProductSales table
INSERT INTO ProductSales(ProductSalesId, ProductId, QuantitySold)
VALUES(@MaxProductSalesId, @ProductId, @QuantityToSell)
END
COMMIT TRANSACTION CHECKTR
END TRY
BEGIN CATCH
ROLLBACK TRANSACTION
SELECT ERROR_NUMBER() as ErrorNumber,
ERROR_MESSAGE() as ErrorMessage,
ERROR_PROCEDURE() as ErrorProcedure,
ERROR_STATE() as ErrorState,
ERROR_SEVERITY() as ErrorSeverity,
ERROR_LINE() as ErrorLine
END CATCH
END
推荐阅读
- android - debug.keystore 丢失。无法在 .androdid 文件夹中找到它
- amazon-web-services - 使用boto3从sqs接收和删除消息
- jquery - 将嵌套的 JSON 对象转换为 Accordion 格式
- rest - gitlab api:获取一个组的所有项目(带有子组)
- c# - 在 MVC 中创建数据库类
- c# - 在显示之前编辑表单的外观
- php - 以编程方式在 wordpress 多站点中创建类别和子类别
- python - 是否可以为鼻子测试提供“设置-geterator-functions”?
- laravel - 如何获得具有两个或多个特定条件的行?
- ruby-on-rails - 从 2.3 切换到 2.4 时出现包更新错误