首页 > 解决方案 > 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 的最后一次插入之后完成。

标签: sql-servertransactionsisolation

解决方案


这个问题原来是进程 1 中的一个 COMMIT,它过早地结束了事务。

进程 1 开始一个事务,然后做一堆工作。部分工作是调用具有 COMMIT 的存储过程。一旦执行此操作,事务就结束了,进程 2 能够继续。

我仍然需要了解为什么进程 1 在执行预期的提交事务时没有抛出错误。

感谢 Piotr 建议使用触发器来获取更多信息。


推荐阅读