IF OBJECT_ID('dbo.Product','U') IS NOT NULL
DROP TABLE dbo.Product
IF OBJECT_ID('dbo.ProductSales','U') IS NOT NULL
DROP TABLE dbo.ProductSales
GO
CREATE TABLE Product
(
ProductID INT PRIMARY KEY,
Name VARCHAR(40),
Price INT,
Quantity INT
)
GO
INSERT INTO Product VALUES(101, 'Laptop', 15000, 100)
INSERT INTO Product VALUES(102, 'Desktop', 20000, 150)
INSERT INTO Product VALUES(103, 'Mobile', 3000, 200)
INSERT INTO Product VALUES(104, 'Tablet', 4000, 250)
GO
CREATE TABLE ProductSales
(
ProductSalesId INT PRIMARY KEY,
ProductId INT,
QuantitySold INT
)
GO
INSERT INTO ProductSales VALUES(1, 101, 10)
INSERT INTO ProductSales VALUES(2, 102, 15)
INSERT INTO ProductSales VALUES(3, 103, 30)
INSERT INTO ProductSales VALUES(4, 104, 35)
GO
SQL Server 中事务的原子性
IF OBJECT_ID('spSellProduct','P') IS NOT NULL
DROP PROCEDURE spSellProduct
GO
CREATE PROCEDURE spSellProduct
@ProductID INT,
@QuantityToSell INT
AS
BEGIN
-- 首先我们需要检查待销售产品的可用库存
DECLARE @StockAvailable INT
SELECT @StockAvailable = Quantity FROM Product WHERE ProductId = @ProductId
--如果可用库存小于要销售的数量,抛出错误
IF(@StockAvailable < @QuantityToSell)
BEGIN
Raiserror('可用库存不足',16,1)
END
-- 如果可用库存充足
ELSE
BEGIN
BEGIN TRY
-- 我们需要开启一个事务
BEGIN TRANSACTION
-- 首先做减库存操作
UPDATE Product SET Quantity = (Quantity - @QuantityToSell) WHERE ProductID = @ProductID
-- 计算当前最大的产品销售ID,即 MaxProductSalesId
DECLARE @MaxProductSalesId INT
SELECT @MaxProductSalesId = CASE
WHEN MAX(ProductSalesId) IS NULL THEN 0
ELSE MAX(ProductSalesId)
END
FROM ProductSales
-- 把 @MaxProductSalesId 加一, 所以我们会避免主键冲突
--(解释下,建表的时候,没有设置主键自增,所以需要人工处理自增)
Set @MaxProductSalesId = @MaxProductSalesId + 1
-- 把销售的产品数量记录到ProductSales表中
INSERT INTO ProductSales VALUES (@MaxProductSalesId, @ProductId, @QuantityToSell)
-- 最后,提交事务
COMMIT TRANSACTION
END TRY
BEGIN CATCH
-- 如果发生了异常,回滚事务
ROLLBACK TRANSACTION
END CATCH
End
END
SQL Server 中事务的一致性
SQL Server 中事务的一致性确保数据库数据在事务开始之前处于一致状态,并且在事务完成后也使数据保持一致状态。如果事务违反规则,则应回滚。例如,如果可用库存从 Product 表中减少,那么 ProductSales 表中必须有一个相关条目。
IF OBJECT_ID('dbo.Product','U') IS NOT NULL
DROP TABLE dbo.Product
IF OBJECT_ID('dbo.ProductSales','U') IS NOT NULL
DROP TABLE dbo.ProductSales
GO
CREATE TABLE Product
(
ProductID INT PRIMARY KEY,
Name VARCHAR(40),
Price INT,
Quantity INT
)
GO
INSERT INTO Product VALUES(101, 'Laptop', 15000, 100)
INSERT INTO Product VALUES(102, 'Desktop', 20000, 150)
INSERT INTO Product VALUES(103, 'Mobile', 3000, 200)
INSERT INTO Product VALUES(104, 'Tablet', 4000, 250)
GO
CREATE TABLE ProductSales
(
ProductSalesId INT PRIMARY KEY,
ProductId INT,
QuantitySold INT
)
GO
INSERT INTO ProductSales VALUES(1, 101, 10)
INSERT INTO ProductSales VALUES(2, 102, 15)
INSERT INTO ProductSales VALUES(3, 103, 30)
INSERT INTO ProductSales VALUES(4, 104, 35)
GO
SQL Server 中事务的原子性
IF OBJECT_ID('spSellProduct','P') IS NOT NULL
DROP PROCEDURE spSellProduct
GO
CREATE PROCEDURE spSellProduct
@ProductID INT,
@QuantityToSell INT
AS
BEGIN
-- 首先我们需要检查待销售产品的可用库存
DECLARE @StockAvailable INT
SELECT @StockAvailable = Quantity FROM Product WHERE ProductId = @ProductId
--如果可用库存小于要销售的数量,抛出错误
IF(@StockAvailable < @QuantityToSell)
BEGIN
Raiserror('可用库存不足',16,1)
END
-- 如果可用库存充足
ELSE
BEGIN
BEGIN TRY
-- 我们需要开启一个事务
BEGIN TRANSACTION
-- 首先做减库存操作
UPDATE Product SET Quantity = (Quantity - @QuantityToSell) WHERE ProductID = @ProductID
-- 计算当前最大的产品销售ID,即 MaxProductSalesId
DECLARE @MaxProductSalesId INT
SELECT @MaxProductSalesId = CASE
WHEN MAX(ProductSalesId) IS NULL THEN 0
ELSE MAX(ProductSalesId)
END
FROM ProductSales
-- 把 @MaxProductSalesId 加一, 所以我们会避免主键冲突
--(解释下,建表的时候,没有设置主键自增,所以需要人工处理自增)
Set @MaxProductSalesId = @MaxProductSalesId + 1
-- 把销售的产品数量记录到ProductSales表中
INSERT INTO ProductSales VALUES (@MaxProductSalesId, @ProductId, @QuantityToSell)
-- 最后,提交事务
COMMIT TRANSACTION
END TRY
BEGIN CATCH
-- 如果发生了异常,回滚事务
ROLLBACK TRANSACTION
END CATCH
End
END
SQL Server 中事务的一致性
SQL Server 中事务的一致性确保数据库数据在事务开始之前处于一致状态,并且在事务完成后也使数据保持一致状态。如果事务违反规则,则应回滚。例如,如果可用库存从 Product 表中减少,那么 ProductSales 表中必须有一个相关条目。