所以我有一组复杂的代码(由其他人编写),它有一个在最终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)。
答案 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.在包含写入的事务中,读取/查询通常(并非总是)是不必要的。
答案 3 :(得分:0)
使用Commit()的正确方法是什么,或者我应该摆脱它而不使用这些事务函数?让代码立即执行所有操作?
不要摆脱交易。它们有意义,旨在使您的数据保持一致。