无法执行事务操作,因为有待处理的请求正在运行

时间:2016-04-11 14:59:02

标签: c# transactions ado.net sqltransaction

背景

我有一些代码可以打开一个sql连接,开始一个事务并在数据库上执行一些操作。此代码从DB(dequeue)创建一个对象,获取一些值并将其保存回来。整个操作需要在交易中进行。所有代码都可以在没有事务的情况下完美运行。

using (var connection = new SqlConnection(connectionString))
{
    connection.Open();
    var transaction = connection.BeginTransaction();
    try
    {                       
        var myObject = foo.Dequeue(connection, transaction);

        var url = myObj.GetFilePathUri(connection, transaction);

        //some other code that sets object values

        myObj.SaveMessage(connection, transaction);
        transaction.Commit(); //error here
    }
    catch(Exception ex)
    {                    
        transaction.Rollback();
        //logging                
    }
    finally
    {
        //cleanup code
    }
}

出列方法代码

public foo Dequeue(SqlConnection connection, SqlTransaction transaction)
{
    using (var command = new SqlCommand(DEQUEUE_SPROC, connection) {CommandType = CommandType.StoredProcedure, Transaction = transaction})
    {
        var reader = command.ExecuteReader();
        if (reader.HasRows)
        {
            reader.Read();
            ID = (Guid) reader["ID"];
            Name = reader["Name"].ToString();
            return this;
        }
        return null;
    }
}

获取路径代码

public string GetFilePathUri(SqlConnection connection, SqlTransaction transaction)
{
    using (var command = new SqlCommand(FILEPATH_SPROC, connection) {CommandType = CommandType.StoredProcedure, Transaction = transaction})
    {
        var reader = command.ExecuteReader();
        if (reader.HasRows)
        {
            reader.Read();
            return reader["Path"].ToString();
        }
        return "";
    }
}

保存代码

public void SaveMessage(SqlConnection connection, SqlTransaction transaction)
{
    using (var command = new SqlCommand(SAVE_SPROC, connection) {CommandType = CommandType.StoredProcedure, Transaction = transaction})
    {
        command.Parameters.Add("@ID", SqlDbType.UniqueIdentifier).Value = ID;
        command.Parameters.Add("@Name", SqlDbType.VarChar).Value = Name;
        //other object params here
        command.ExecuteNonQuery();
    }
}

问题

调用transaction.Commit()时,出现以下错误:

  

无法执行事务操作,因为存在处理此事务的待处理请求。

我做错了什么?

编辑:快速编辑,说我已经在SO上阅读了有关此问题的其他问题,但无法找到与ADO.net相关的任何问题

3 个答案:

答案 0 :(得分:19)

之前我遇到过这个问题,问题是读者需要关闭。 试试这个:

tar -xvf spark-1.4.1.tgz
sbt/sbt assembly

答案 1 :(得分:1)

当我忘记对正在执行DB调用的异步方法使用await时,我遇到了这个问题-因为事务在尝试处理所有事务之前没有等待查询完成,所以在事务运行时正在断开连接

答案 2 :(得分:0)

我们遇到了这个问题,虽然接受的答案可能会奏效,但这并不是最正确的做法——但是,它确实为我们提供了关于我们做错了什么的线索。

在我们的例子中,需要读取更多数据。这是问题的简化版本(使用 Dapper):

public Foo GetFooById(int fooId, IDbTransaction transaction = null) {
  var sql = @"
    SELECT * FROM dbo.Foo    WHERE FooID = @FooID;
    SELECT * FROM dbo.FooBar WHERE FooID = @FooID;
    SELECT * FROM dbo.FooBaz WHERE FooID = @FooID;
  ";

  using var data = await _connection.QueryMultipleAsync(sql, new { fooId }, transaction);
  var foo = data.ReadSingle<Foo>();
  foo.Bars = data.Read<Bar>();
  // Oops, didn't read FooBar.
  return foo;
}

即使 data 被释放,它也会在事务上留下一个“待处理的请求”,然后在调用 transaction.Commit() 时它会爆炸。

解决方案是从 FooBaz 中读取 data 条记录,或者去掉未读取的 SELECT