DbTransaction.Commit回滚,导致代码中断?

时间:2011-08-17 18:08:36

标签: c# asp.net database

所以我有一组复杂的代码(由其他人编写),它有一个在最终Commit()更改之前执行大量数据库操作的函数。

这是问题所在,代码中有子函数,如getThis或getThat,它们具有execute()和queryDatabase()函数。代码在某些情况下(并非所有情况)都会导致错误,它会在此“执行”或“查询数据库”中冻结。从本质上讲,我认为这与在提交更改之前代码需要来自这些queryDatabase命令的数据这一事实有关。

删除向这些子函数传递dataAccess指针后(因此它们不是提交的一部分),突然代码成功通过。

使用Commit()的正确方法是什么,或者我应该摆脱它而不使用这些事务函数​​?让代码立即执行所有操作?

我甚至找不到最后一个错误,只是另一个模糊的“连接参数null”SystemArgumentNullException,它以某种方式连接到它是一个事务。

System.ArgumentNullException: Value cannot be null
Parameter name: connection
at Data.Database.PrepareCommand(DbCommand command, DbConnection connection)

发布代码很难,因为它至少包含20个不同的文件(是的,原始开发人员不知道KISS)。

4 个答案:

答案 0 :(得分:2)

事务提交后,Transaction.Connection将设置为null,这可能是如果代码传递Transaction.Connection作为对所有子功能的引用,则连接设置为null的原因。事务不拥有连接,因此不应将其传递给其他子功能。

听起来好像是连接遍布整个地方。更好的方法是将连接放在using块中,并且只在using块中放置需要该连接的命令以及与之相关的事务。

这是一个基本模式:

using(DbConnection connection = ...)

{

    connection.Open();

    using(DbTransaction transaction = connection.BeginTransaction(...))

    {

        ... do stuff ...

        transaction.Commit();        

    } // transaction rolled back here if an Exception is thrown before the call to Commit()

} // connection closed here

如果代码保存到多个表/记录,则必须进行事务处理。工作单元需要作为一个整体而不是部分地进行。摆脱事务的一种方法是让数据库通过存储过程直接管理它们。 BEGIN TRAN在存储过程中显式完成,此时C#代码不再管理它。

另请查看System.Transactions命名空间。我认为它比管理连接本身的事务更容易使用。

答案 1 :(得分:1)

在DbTransaction.Commit()/ Rollback()之后,事务对象进入“僵尸”状态。 如果您计划继续使用事务范围之外的某些命令,则必须通过将Transaction属性设置为null来将其与事务分离

答案 2 :(得分:1)

事务通常应该用于逻辑上代表单个工作单元的一组操作。换句话说,如果在事务中执行了三个操作,并且其中一个操作失败或调用了Rollback,则结果应该反映实际发生在数据库中的三个操作的 none 。 / p>

因此,在您决定删除事务之前,您需要确定原始开发人员和代码的意图(这可能并不容易!)。如果操作需要一起成功或失败,则需要继续使用该事务。如果每个操作都可以自行成功或失败,那么您可能完全摆脱该事务,因为大多数数据库都有单个调用的隐式事务。

一些经验法则:1。交易费用昂贵 - 尽可能晚地启动它们并尽早提交; 2.在包含写入的事务中,读取/查询通常(并非总是)是不必要的。

Database Transactions

答案 3 :(得分:0)

  

使用Commit()的正确方法是什么,或者我应该摆脱它而不使用这些事务函数​​?让代码立即执行所有操作?

不要摆脱交易。它们有意义,旨在使您的数据保持一致。