2010-05-21 35 views
1

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

今天对我来说似乎有点不可能,我偶然到一个问题,但它的发生......我打电话给在C#中的一些数据库的代码看起来是这样的:

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

tran.Commit(); 
} 

我已经简化了这一点发布,但是发生了什么是MyDataLayer.Transaction()使IsolationLevel设置为快照和TransactionScopeOption设置为必需的TransactionScope。这段代码每天被调用数百次,并且几乎总能完美运行。然而,在查看一些数据后,我发现有一些由“SprocTheFirst”创建的记录,但没有来自“CallSomethingThatEventuallyDoesLinqToSql”的相应数据。记录应该存在于我看到的表中的唯一方法是从SprocTheFirst,并且它唯一的一次调用这个函数,所以如果它的调用和成功,那么我会期待CallSomethingThatEventuallyDoesLinqToSql将被调用并成功,因为它的全部在同样的TransactionScope。理论上可能有其他一些开发人员在数据库中徘徊,但我认为他们没有。我们还记录了所有的例外情况,并且在创建SprocTheFirst记录的时候没有发现任何异常情况。

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

+0

是否是TransactionScope?它不应该是'tran.Complete();'? – 2010-05-29 03:17:21

回答

0

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

至少这就是我如何理解你的问题。如果不是,请提供更多信息,比如时间表的图片或类似的东西。

+0

我发现它发生后的几天有异常的数据,所以当我发现它时,我并没有从乐观锁中得到一个有趣的结果。 据我了解,我所看到的事情不应该发生,我更多地问是否有其他人以前看过类似的东西。如果没有,那么可能有一些真的很难追踪我的代码,但如果其他人已经注意到这一点,那么这可能表明在我的代码之外的更低级别的错误。 – 2010-05-23 04:10:43

0

您可以验证CallSomethingThatEventuallyDoesLinqToSQL是否使用与第一次调用相同的连接?第二次调用是否读取第一次提交到数据库的数据......并且如果它无法“看到”该数据会导致第二次跳过几个步骤而不执行它的工作?

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

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

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

+0

看到这个... http://stackoverflow.com/questions/1707566/data-committed-even-though-system-transactions-transactionscope-commit-not-call – ripvlan 2010-05-25 21:33:45

0

这听起来像你的连接可能不会被列入交易。你什么时候创建连接对象?如果它发生在TransactionScope之前,那么它不会在事务中注册。

1

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

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