当前位置:  开发笔记 > 数据库 > 正文

SqlTransaction已经完成

如何解决《SqlTransaction已经完成》经验,为你挑选了3个好方法。

我有一个应用程序可能会对SQL Server 2005数据库进行数千次插入.如果插入因任何原因(外键约束,字段长度等)而失败,则应用程序将记录插入错误并继续.

每个插入都独立于其他插入,因此数据库完整性不需要事务.但是,我们希望使用它们来提高性能.当我使用事务时,我们将在每100次提交中大约有1次出现以下错误.

This SqlTransaction has completed; it is no longer usable.
   at System.Data.SqlClient.SqlTransaction.ZombieCheck()
   at System.Data.SqlClient.SqlTransaction.Commit()

为了尝试追踪原因,我在每个事务操作中都放置了trace语句,这样我就可以确保在调用commit之前没有关闭事务.我已经确认我的应用程序不会关闭交易.然后我使用完全相同的输入数据再次运行应用程序并成功.

如果我关闭日志,它会再次失败.把它重新打开,然后成功.这个开/关切换是通过app.config完成的,无需重新编译.

显然,记录行为会改变时间并使其起作用.这表明存在线程问题.但是,我的应用程序不是多线程的.

我已经看到一个MS KB条目表明.Net 2.0框架的错误可能会导致类似的问题(http://support.microsoft.com/kb/912732).但是,他们提供的修复程序无法解决此问题.



1> aef123..:

感谢所有的反馈.我一直在MSDN论坛上与MSFT的某个人合作,以弄清楚发生了什么.事实证明,问题是由于日期时间转换问题导致其中一个插入失败.

主要问题是,如果是日期转换错误,则会显示此错误.但是,如果它是另一个错误,例如字段太长,则不会导致此问题.在这两种情况下,我都希望事务仍然存在,所以我可以在其上调用Rollback.

我有一个完整的示例程序来复制此问题.如果有人希望看到它或与MSFT交换,您可以在SqlTransaction.ZombieCheck错误线程下的microsoft.public.dotnet.framework.adonet中的MSFT新闻组中找到该线程.


最终结果是SQL Server自动回滚了它认为严重错误的事务.DateTime转换错误被认为是这些严重错误之一.目前没有办法阻止SQL Server终止您的事务以获得此类错误.

2> Joe..:

没有看到代码就很难提供帮助.我假设您在描述中使用事务在每N个插入后提交,这将提高性能与提交每个插入,前提是N不是太大.

但缺点是:如果插入失败,当您回滚事务时,当前批次N中的任何其他插入将被回滚.

通常,您应该在关闭连接之前处置事务(如果事务尚未提交,则会回滚事务).通常的模式类似于以下内容:

using(SqlConnection connection = ...)
{
    connection.Open();
    using(SqlTransaction transaction = connection.BeginTransaction())
    {
        ... do stuff ...
        transaction.Commit(); // commit if all is successful
    } // transaction.Dispose will be called here and will rollback if not committed
} // connection.Dispose called here

如果您需要更多帮助,请发布代码.



3> Bevan..:

请记住,您的应用程序不是事务的唯一参与者 - 也涉及SQL Server.

你引用的错误:

这个SqlTransaction已经完成; 它不再可用.System.Data.SqlClient.SqlTransaction.Commit()中的System.Data.SqlClient.SqlTransaction.ZombieCheck()

并不表示交易已经完成,只是表示已完成.

我的第一个建议是你的服务器已经终止了交易,因为它要么花费太长时间(耗尽时间)或者太大(更改太多或锁太多).

我的第二个建议是检查您是否正确清理了连接和交易.您可能会遇到问题,因为在事情自动回收之前,您偶尔会耗尽一些资源.

例如,DbConnection实现IDisposable,因此您需要确保适当地清理 - 如果可以,使用using语句,或者如果不能,则通过Dispose()直接调用.'DbCommand'类似,因为它也实现了IDisposable.

推荐阅读
ar_wen2402851455
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有