sql - 同时发生的事务会产生错误的选择结果
问题描述
我有一个 SQL 数据库来跟踪库存中的项目。物品有数量,可以签出。
我有一个包含 OnHandQty 和 OutQty的项目表。
每当发生结帐时,我都会在我的ItemHistory表中存储一条记录并更新我的Items表中的数量值以反映更改。
在同时将大量事务发送到服务器之前,这非常有效。
我的结帐查询如下所示:
BEGIN TRY
BEGIN TRANSACTION
DECLARE @OnHand [int]
DECLARE @Out [int]
SELECT @OnHand = QtyOnHand, @Out = QtyOut
FROM [Item]
IF (((-@qty) + @OnHand) >= 0)
BEGIN
INSERT INTO [dbo].[ItemHistory] (...)
OUTPUT Inserted.ItemID
VALUES(...)
UPDATE [Item]
SET
QtyOnHand = @OnHand - @qty,
QtyOut = @Out + @qty
END
ELSE
BEGIN
ROLLBACK TRAN
END
COMMIT
END TRY
BEGIN CATCH
IF @@TRANCOUNT > 0
ROLLBACK TRAN
END CATCH
问题出现在这里:
SELECT @OnHand = QtyOnHand, @Out = QtyOut
FROM [Item]
服务器有时会同时开始两个事务。这会导致@OnHand和@Out变量在两个单独的事务中完全相同。这不好,因为这些应该代表当前的总数。他们在技术上是这样做的,因为此时服务器还没有时间更新Item表。
我需要这个选择来获得绝对电流量以使其工作。
有没有办法防止交易同时发生?或者有没有更好的方法来处理这个过程?
解决方案
在 SQL Server 中处理并发问题的两种可能方法是:
1)在表上获取排他表锁with (tablockx)
,例如
SELECT @OnHand = QtyOnHand, @Out = QtyOut FROM [Item] WITH (tablockx)
2)sp_getapplock
用于创建单个用户代码块。
注意:请记住,强制单用户访问此代码块会降低数据库的性能吞吐量。所以你想让这些锁尽可能短。
推荐阅读
- leaflet - 从 Leaflet.js 地图手动写入世界文件 (jgw)
- java - 使用 JavaFx 应用程序中的 args 执行 Runnable Jar
- java - Java动态添加按钮到面板
- c - Linux下,ARP请求包通过哪个接口出去?
- entity-framework - 更新实体而不读取 EF 核心中的整个实体
- python - urlopen:AttributeError:“字节”对象没有属性“超时”
- python - 如何按数字顺序而不是基于 y 轴值绘制熊猫条形图的 x 轴
- c# - 从 SQL Server 加载数据时 C# WCF 服务随机崩溃
- javascript - i18next - 应用自定义格式
- javascript - 在普通 TypeScript 文件中导入 Vue 组件失败