“操作对事务的状态无效”错误和事务范围

Posted

技术标签:

【中文标题】“操作对事务的状态无效”错误和事务范围【英文标题】:"The operation is not valid for the state of the transaction" error and transaction scope 【发布时间】:2010-09-16 15:04:53 【问题描述】:

当我尝试调用包含 SELECT 语句的存储过程时出现以下错误:

该操作对交易状态无效

这是我的调用结构:

public void MyAddUpdateMethod()


    using (TransactionScope Scope = new TransactionScope(TransactionScopeOption.RequiresNew))
    
        using(SQLServer Sql = new SQLServer(this.m_connstring))
        
            //do my first add update statement

            //do my call to the select statement sp
            bool DoesRecordExist = this.SelectStatementCall(id)
        
    


public bool SelectStatementCall(System.Guid id)

    using(SQLServer Sql = new SQLServer(this.m_connstring)) //breaks on this line
    
        //create parameters
        //
    

我在事务中创建到同一个数据库的另一个连接有问题吗?

【问题讨论】:

【参考方案1】:

在做了一些研究之后,似乎我无法使用 TransactionScope 块打开到同一个数据库的两个连接。我需要修改我的代码如下所示:

public void MyAddUpdateMethod()

    using (TransactionScope Scope = new TransactionScope(TransactionScopeOption.RequiresNew))
    
        using(SQLServer Sql = new SQLServer(this.m_connstring))
        
            //do my first add update statement            
        

        //removed the method call from the first sql server using statement
        bool DoesRecordExist = this.SelectStatementCall(id)
    


public bool SelectStatementCall(System.Guid id)

    using(SQLServer Sql = new SQLServer(this.m_connstring))
    
        //create parameters
    

【讨论】:

我偶然发现了同样的情况。我必须在同一个事务范围内引用两个不同的数据库。感谢您的提示。 很好,看到这种情况的常见地方是如果您有一个正在写入数据库的日志框架(nlog,log4net),因为日志框架将创建自己的与数据库的连接你的应用程序。 日志记录应用程序应该可能抑制任何外部 TransactionScope 上下文。 NLog 抑制任何外部 TransactionScope:github.com/NLog/NLog/wiki/Database-target 我在同一 TransactionScope 下使用 using 语句打开了两次相同的连接,但仍然有效。我使用 SqlConnection 而不是上面示例中使用的 SQLServer。【参考方案2】:

当我遇到这个异常时,出现了 InnerException "Transaction Timeout"。由于这是在调试会话期间,当我在 TransactionScope 内暂停代码一段时间时,我选择忽略此问题。

当这个特定的超时异常出现在部署的代码中时,我认为 .config 文件中的以下部分会帮助你:

<system.transactions> 
        <machineSettings maxTimeout="00:05:00" /> 
</system.transactions>

【讨论】:

TransactionOptions.Timeout一样吗? 请注意,当超过 10 分钟时,有一个机器范围的 .NET 框架配置会否决这一点!【参考方案3】:

我也遇到了同样的问题,我将事务超时更改为 15 分钟,它可以工作。 我希望这会有所帮助。

TransactionOptions options = new TransactionOptions();
options.IsolationLevel = System.Transactions.IsolationLevel.ReadCommitted;
options.Timeout = new TimeSpan(0, 15, 0);
using (TransactionScope scope = new TransactionScope(TransactionScopeOption.Required,options))

    sp1();
    sp2();
    ...


【讨论】:

我强烈怀疑不是超时改变了行为,而是您将隔离级别从 Serializable 更改为 ReadCommitted。 超时的情况下也会出现这个异常,异常数据中也要包含超时的信息【参考方案4】:

当我的事务嵌套在另一个事务中时,我遇到了这个错误。是存储过程声明了自己的事务还是调用函数声明了一个?

【讨论】:

我的任何存储过程中都没有任何 t-sql 事务代码。理论上,事务应该由 MyAddUpdateMethod() 控制 +1 因为我在存储过程中的事务语言错误时收到此错误,即事务计数被弄乱了。【参考方案5】:

对于将来遇到这种情况的任何流浪者。如果您的应用程序和数据库位于不同的机器上,并且您遇到上述错误,尤其是在使用 TransactionScope 时,请启用网络 DTC 访问。执行此操作的步骤是:

    添加防火墙规则以允许您的计算机相互通信。 确保分布式事务协调器服务正在运行 启用网络 dtc 访问。运行 dcomcnfg。转到组件服务 > 我的电脑 > 分布式事务协调器 > 本地 DTC。右键单击属性。 如图所示启用网络 dtc 访问。

重要提示:请勿编辑/更改 DTC 登录帐户字段中的用户帐户和密码,保持原样,否则将最终重新安装 windows。

【讨论】:

@KJN 谢谢!我们应该在 SQL Server 工作的机器上这样做吗? 是的,在运行 sql server 的地方进行。【参考方案6】:

对我来说,当我在另一个事务块内遇到异常后尝试回滚事务块时出现此错误。

我所要做的就是删除我的内部事务块。

使用嵌套事务时事情可能会变得非常混乱,最好避免这种情况并重新构建您的代码。

【讨论】:

【参考方案7】:

在我的情况下,解决方案既不是增加“transactionscope”的时间,也不是增加machine.config文件的“system.transactions”的“machineSettings”属性的时间。

在这种情况下发生了一些奇怪的事情,因为这个错误只发生在信息量非常大的时候。

所以问题是基于这样一个事实,即在事务内部的代码中有许多“foreach”对不同的表进行更新(我必须在其他人员开发的代码中解决这个问题)。如果对表中的记录很少进行测试,则不会显示错误,但如果记录数增加,则会显示错误。

最终解决方案是从单个事务更改为事务内不同“foreach”中的多个单独事务。

【讨论】:

【参考方案8】:

您不能同时打开两个交易。我所做的是在返回将由第二个事务使用的结果之前指定 transaction.Complete() ;)

【讨论】:

【参考方案9】:

我更新了一些处理部分数据库进程的专有第 3 方库,并且在所有保存调用时都出现此错误。我不得不更改 web.config 事务键部分中的一个值,因为(事实证明)引用的事务范围方法已从一个库移动到另一个库。

以前还有其他与该键相关的错误,但我通过注释掉该键来消除它们(我知道我当时应该怀疑,但我认为它现在是多余的,因为它不在闪亮的新图书馆)。

【讨论】:

以上是关于“操作对事务的状态无效”错误和事务范围的主要内容,如果未能解决你的问题,请参考以下文章

事务并发事务隔离级别

Postgresql 捕获事务错误和回滚

C# 中的事务和 ExecuteNonQuery 错误

更新错误和回滚事务

mvc中的ajax和事务错误

MySQL 错误:超过锁定等待超时;尝试重新启动事务查询