有没有办法使用通用DbCommand进行异步更新?

时间:2009-05-11 15:26:46

标签: c# oracle ado.net idbcommand oraclecommand

使用通用DbCommand执行更新时,如果正在更新的行被锁定,它将无限期挂起。

使用的底层连接是Devart的Oracle提供程序Devart.Data.Oracle.OracleConnection

设置DbCommand.CommandTimeOut完全没有效果,更新永远不会超时。

DbCommand没有实现BeginExecuteNonQuery,因此似乎无法以异步方式使用DbConnection / DbCommand。

我可以通过使用Devart的OracleCommand和BeginExecuteQuery解决这个问题,但确实如此。

有没有办法以通用方式执行此操作?

oracle特定逻辑的简化代码:

public bool TestAsyncUpdateRowOracle(string key, OracleConnection con, string sql)
{
    const int timoutIterations=10;
    bool updateOk=false;
    OracleCommand cmd = new OracleCommand(sql, con);
    cmd.Parameters.Add(Util.CreateParameter(dbSrcFactory, DbType.String, 16, "key"));
    cmd.CommandType = CommandType.Text;
    cmd.Parameters[0].Value = key.ToString();

    IAsyncResult result = cmd.BeginExecuteNonQuery();
    int asyncCount = 0;
    while (!result.IsCompleted)
    {
        asyncCount++;
        if (asyncCount > timeoutIterations)
        {
            break;
        }
        System.Threading.Thread.Sleep(10);
    }

    if (result.IsCompleted)
    {
        int rowsAffected = cmd.EndExecuteNonQuery(result);
        Console.WriteLine("Done. Rows affected: " + rowsAffected.ToString());
    }
    else
    {
        try
        {
            cmd.Cancel();
            Console.WriteLine("Update timed out, row is locked");

        }
        catch (Exception e)
        {
            Console.WriteLine(e.ToString());
            Console.WriteLine("Unable to cancel update");
        }
    }
    cmd.Dispose();
}

2 个答案:

答案 0 :(得分:2)

可悲的是,不,ADO.NET中没有具有异步操作的接口或基类(例如BeginExecuteNonQuery / EndExecuteNonQuery)。它们仅存在于极少数ADO.NET提供程序实现中。 (SqlClient,Devart Oracle)。

也就是说,如果在设置CommandTimeOut时它没有超时,我认为这是提供者中的一个错误。

答案 1 :(得分:0)

您可以使用NOWAIT选项发出LOCK TABLE吗?如果锁定失败,这将立即向您返回控制错误。例如:

LOCK TABLE employees
   IN EXCLUSIVE MODE 
   NOWAIT; 

有几种方法可以锁定表格。 Here是关于锁定的开发人员指南部分。 This是LOCK TABLE命令的SQL Reference页面。

另一种选择是使用SELECT .. FOR UPDATE NOWAIT语句来锁定要更新的行。除了更新语句之外,这两个选项都需要向Oracle发出其他命令。