1

当使用通用 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();
}
4

2 回答 2

2

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

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

于 2010-09-15T23:08:22.663 回答
0

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

LOCK TABLE employees
   IN EXCLUSIVE MODE 
   NOWAIT; 

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

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

于 2009-05-11T17:58:00.513 回答