来自C#的并发进程的SQL事务奇数

时间:2010-02-24 09:42:03

标签: c# transactions isolation-level

我们有一个C#系统抛出一个奇怪的东西,我们无法深入了解SQL(SQL2k5)。

情况是我们有两个独立的进程同时运行查看同一个表,这两个进程在两个不同集群上的两个不同的服务COM +组件中运行它们自己的事务。两者都在与OrderOrderItem SQL表进行通信。两者都以READ COMMITTED隔离级别运行。

  

工作1:加载订单和一个或   这些表格中有更多项目。

     

作业2:发生的计划任务   每隔几分钟从选择中选择   查找所有订单的表格   已经完全处理。

问题:我们发现在过去八个月中,作业2已经四次对作业1的部分加载订单作出反应,作业1完全完成之前(作为项目订单没有库存,处于完工状态,因此作业可以看到订单的其余部分尚未加载。

从调查开始,虽然工作1正在进行中,但我们无法做到:

  

从订单中选择*

一旦订单被插入其中。但是,我们可以这样做:

  

在oi.orderid = o.id上选择* fromOrder o inner join OrderItem oi

同时(为什么会这样?)。

在调查复制相同的情况时,我们无法获得作业2来查看来自作业1的部分创建的订单,它确实返回了一些行但从未通过作业1插入订单。但是,这正是发生在我们的现场环境!

有没有人知道为什么会这样?

2 个答案:

答案 0 :(得分:0)

我会尝试回滚作业1执行的一些工作作为实验,以确认在回滚发生时实际上已删除了您认为包含在事务中的所有内容。我和您一样,怀疑您将永远无法从不同的事务中读取数据,这些数据将在使用READ COMMITTED时通过回滚删除。您能够读取行的事实表明它们中的一些可能会在事务的上下文之外进行。

我的下一个想法是审查READ COMMITTED的含义。这种隔离级别可以确保您正在读取的数据已由一个事务提交,但不一定能确保它仍然不会因另一个事务而发生更改。将此与REPEATABLE READ对比,其中所有数据保持锁定直到事务结束,或SERIALIZABLE,其尝试表现为所有事务按顺序执行。我怀疑如果你将锁定更改为SERIALIZABLE(限制性最强),这个特殊问题就不会发生,但这可能有点过头了。

在考虑了READ COMMITTED与其他隔离级别相比的含义之后,我怀疑你所看到的行为在这个隔离级别是很自然的,因为你插入的行实际上就是那些仍然存在的行。交易结束。我认为READ COMMITTED并不是为了确保查询返回一组完整的行(这需要SERIALIZABLE强加的范围锁定),而只是确保您正在读取的各行已经完全插入(所以你'不读部分行)。我可能是错的,但鉴于你描述的行为,这是我的怀疑。如果你需要确保整个行集完整,我认为你需要SERIALIZABLE隔离。

哪个交易需要SERIALIZABLE?显然,如果它们都是SERIALIZABLE,那应该可行。但有可能只使其中一个SERIALIZABLE仍然得到正确的行为。我目前的精神力量无法确定真正需要什么可串行化的任务,但也许其他人的一些评论会带来额外的亮点。

答案 1 :(得分:0)

问题在于,当您打开事务并添加几行时,这些行将被锁定,直到提交事务为止。

当您SELECT *执行包含锁定行的选择时,在允许您进行SELECT之前,您必须通过提交或回滚事务来解锁它们。