sql-server - C# 和 T-SQL 之间的 SQL 事务重叠
问题描述
我有一个 C# 进程将记录插入事务中的表中。在此期间,另一个进程(SQL 存储过程)正在更新此表。C# 进程使用可序列化隔离模式,SP 使用读提交。
正在更新的表有一个名为 DateShipped 的日期时间字段,C# 进程使用当前时间插入该字段。C# 进程大约需要 1 秒来确定要使用的值并执行插入语句。查看表中的数据,您可以看到在事务中添加的所有记录在 DateShipped 字段中都有大约 1 秒的差异。让我们不要担心如何使这个过程变得更好。我目前关心的是了解 SP 如何能够更新另一个进程的事务中且尚未提交的记录。
表中还有另一个字段 TransID 定义为 INT。C# 进程在插入时未指定此字段的值,因此默认为 NULL。SP 按计划运行,它所做的第一件事是将 TransID 为 NULL 的所有记录更新为指定值。SP 在显式事务中运行。
有时(不确定是否总是因为我不知道它们在同一时间运行的频率)当同一事务中的其他记录(第一个这么多)使用 TransID 更新时不要。
SP怎么能看到第一个这么多记录,但不是全部?
有没有办法使用扩展事件来捕获这个?
插入结果:
DateShipped TransID
2020-02-12 00:26:47.680 514928
2020-02-12 00:26:49.090 514929
2020-02-12 00:26:50.057 514929
2020-02-12 00:26:51.027 514929
2020-02-12 00:26:51.963 514929
2020-02-12 00:26:52.887 514929
2020-02-12 00:26:53.807 514929
2020-02-12 00:26:54.747 514929
2020-02-12 00:26:55.713 514929
2020-02-12 00:26:56.700 514929
2020-02-12 00:26:57.700 514929
2020-02-12 00:26:58.653 514929
2020-02-12 00:26:59.620 514929
2020-02-12 00:27:00.573 514929
有人可以推荐一种方法来防止这种情况(从不同的事务更新未提交的插入)或捕获相关信息以显示这种情况正在发生吗?
附加信息
处理 1 代码 (c#)
ADODB.Connection.BeginTrans()
... Several inline SELECTs and INSERTs via ADODB.Connection.Execute()
ADODB.Connection.CommitTrans()
插入将 DateShipped 字段设置为当前日期/时间。所以 DateShipped 是插入的日期/时间。
流程 2 代码(存储过程)
BEGIN TRANSACTION
SELECT @ID = (MAX(TransID) + 1) FROM dbo.tHostInterfaceExport
INSERT INTO dbo.tHostInterfaceExport ( TransID ) VALUES (@ID)
EXEC dbo.dloc_UpdateActivityTables @ID
COMMIT TRANSACTION
程序 dbo.dloc_UpdateActivityTables @TransID INT
UPDATE dbo.tActivityShipments
SET TransID = @TransID
WHERE TransID IS NULL
问题是这个 UPDATE 语句有时(可能只有当 2 个进程同时运行时)只更新插入到进程 1 中的一些第一条记录。
这是发生问题的另一个数据示例。所有这些记录都写在流程 1 的同一事务中。
DateShipped TransID
2020-02-12 10:54:29.157 244878
2020-02-12 10:54:30.063 244878
2020-02-12 10:54:30.940 244878
...
2020-02-12 10:56:31.290 244878
2020-02-12 10:56:31.867 244878
2020-02-12 10:56:32.493 244878 <-- why was this one and the above ones updated
2020-02-12 10:56:33.087 244879 <-- and not this one and the ones below?
2020-02-12 10:56:33.730 244879
2020-02-12 10:56:34.353 244879
...
2020-02-12 10:57:32.360 244879
2020-02-12 10:57:33.093 244879
2020-02-12 10:57:33.970 244879
关于何时创建 TransID 的附加信息。TransID 是在进程 2 开始时创建的。这表明进程 2 在 2 个单独的时间和 3 分钟之间被调用。
TransID DateCreated
244878 2020-02-12 10:54:56.817
244879 2020-02-12 10:57:56.880
这里有趣的是进程 2 计划每 60 秒运行一次,但在完成 TransID 244878 之前它被暂停(等待进程 1 完成并提交事务)。我这样说是因为 TransID = 244879 的条目应该发生在10:55:56 或 10:56:56,但该进程仍在等待上一次更新,该更新被插入事务阻塞,该事务在 10:57:33.970 的最后一次插入之后完成。
解决方案
这个问题原来是进程 1 中的一个 COMMIT,它过早地结束了事务。
进程 1 开始一个事务,然后做一堆工作。部分工作是调用具有 COMMIT 的存储过程。一旦执行此操作,事务就结束了,进程 2 能够继续。
我仍然需要了解为什么进程 1 在执行预期的提交事务时没有抛出错误。
感谢 Piotr 建议使用触发器来获取更多信息。
推荐阅读
- java - 在java中逐字反转字符串(不使用StringBuilder)
- python - 访问字典列表中的值
- python - 更改熊猫列中的数字字符串
- sql - 为注册编写 SQL 查询
- jquery - 一般错误:1364 字段没有默认值
- html - 固定侧边栏内的狮身人面像雪花石膏主题滚动
- javascript - 在客户端转义编码的 base 64 字符串,以便它可以在服务器端正常工作和读取
- reactjs - 什么是最好的反应钩子,频率代码或性能
- asp.net - 在 plesk 上发布 asp.net 网站时出错
- python - numpy 数组中非唯一行的快速组合,映射到列(即快速数据透视表问题,没有 Pandas)