Snapshot事务是否会失败并且只能在TransactionScope中部分提交?

时间:2010-05-21 23:04:36

标签: c# .net sql sql-server transactions

问候

我今天偶然发现了一个对我来说似乎不太可能的问题,但它正在发生......我在c#中调用了一些看起来像这样的数据库代码:

using(var tran = MyDataLayer.Transaction())
{
 MyDataLayer.ExecSproc(new SprocTheFirst(arg1, arg2));
 MyDataLayer.CallSomethingThatEventuallyDoesLinqToSql(arg1, argEtc);

 tran.Commit();
}

我已经对发布进行了简化,但最新情况是MyDataLayer.Transaction()使TransactionScope的IsolationLevel设置为Snapshot,TransactionScopeOption设置为Required。这段代码每天被调用数百次,几乎总是完美无缺。然而,在查看了一些数据之后,我发现有一些由“SprocTheFirst”创建的记录,但没有来自“CallSomethingThatEventuallyDoesLinqToSql”的相应数据。记录应该存在于我正在查看的表中的唯一方法是来自SprocTheFirst,并且它只在这一个函数中被调用,所以如果它被调用并成功,那么我希望CallSomethingThatEventuallyDoesLinqToSql将被调用并成功,因为它全部在相同的TransactionScope。它的理论上可能是其他一些开发人员在数据库中乱码,但我不认为他们有。我们还记录了所有异常,我发现在创建SprocTheFirst的记录的过程中没有发生任何异常情况。

那么,具有快照隔离级别的事务或更正确的声明式TransactionScope是否可能以某种方式失败并且只能部分提交?

4 个答案:

答案 0 :(得分:1)

我们发现了同样的问题。我在这里重新创建了它 - https://github.com/DavidBetteridge/MSMQStressTest

对于我们来说,我们在从队列中读取而不是写入队列时会看到问题。我们的解决方案是更改要序列化的订户中第一个读取的隔离级别。

答案 1 :(得分:0)

不,但快照隔离级别与serializable不同。 快照行存储在tempdb中,直到行提交为止。 所以其他一些交易可以很好地读取旧数据。

至少那是我理解你的问题的方式。如果没有,请提供更多信息,如时间轴的grapf或类似的东西。

答案 2 :(得分:0)

您能否验证CallSomethingThatEventuallyDoesLinqToSQL使用与第一次呼叫相同的Connection?第二次调用是否读取了第一次归档到数据库中的数据...并且如果它无法“看到”数据会导致第二次跳过几步而不执行它的工作?

仅仅因为你将它包装在.NET事务中并不意味着db中看到的数据在连接之间是相同的。例如,您可以连接到两个不同的数据库,并希望在两个数据库失败时回滚,或者将文件数据回滚到数据库并向MSMQ发送消息...如果MSMQ操作失败,它也会回滚数据库操作。 .NET事务将为您处理这项多技术功能。

我确实记得早期版本的ADO.NET(可能是3.0)中的一个问题,其中池化连接代码将分配新的数据库连接,而不是在使用.NET级别TransactionScope时使用当前连接代码。我相信它完全用3.5实现(我可能有我的版本错误..可能是3.5和3.5.1)。它也可能是由MyDataLayer以及它如何分配连接引起的。

使用SQL事件探查器跟踪这些操作,并确保在同一个spid上完成工作。

答案 3 :(得分:0)

听起来您的连接可能未在交易中登记。你什么时候创建你的连接对象?如果它发生在TransactionScope之前,那么它将不会在事务中登记。