1

OracleCommand.CommandTimeout 的ODP.NET文档说

默认值为 0 秒,表示没有时间限制。

当指定的超时值在命令执行完成之前到期时,命令会尝试取消。如果取消成功,则抛出异常并显示 ORA-01013 消息:用户请求取消当前操作。如果命令及时执行且没有任何错误,则不会抛出异常。

在多个 OracleCommand 对象使用同一连接的情况下,其中一个 OracleCommand 对象的超时到期可能会终止单个连接上的任何执行。要使 OracleCommand 的超时到期仅取消其自己的命令执行,只需在 OracleCommand 将 CommandTimeout 属性设置为大于 0 的值时为每个连接使用一个 OracleCommand。

但是这样的代码有效:

static void Main(string[] args)
{
    OracleConnection conn = null;
    try
    {
        string connString =
            "Data Source=(DESCRIPTION=(ADDRESS_LIST=(ADDRESS=(PROTOCOL=TCP)(HOST=myOracleHost)(PORT=1521)))(CONNECT_DATA=(SERVICE_NAME=myServiceName)));User Id=system;Password=admin;Pooling = False;";
        string cmdString1 = "UPDATE employee SET empname = 'temp1' where id = 1";
        string cmdString2 = "Update employee set empname = 'temp2' where id = 2";
        conn = new OracleConnection(connString);
        var cmd1 = new OracleCommand(cmdString1, conn);
        cmd1.CommandTimeout = 30;
        var cmd2 = new OracleCommand(cmdString2, conn);
        cmd2.CommandTimeout = 30;
        conn.Open();
        try
        {
            //Locked the row with ID 1 with an uncommitted update operation outside this code
            cmd1.ExecuteNonQuery();
        }
        catch (Exception exception)
        {
            //Exception ORA-01013 Thrown as expected
        }
        try
        {
            //As per the documentation, this should not also work since this command object also uses the same connection as above and it timed out in the query above
            cmd2.ExecuteNonQuery();
            //But this still works fine. 
        }
        catch (Exception)
        {
            //no exception
        }
    }
    finally
    {
        conn.Close();
    }
}

OracleConnection对两个命令对象使用相同的对象 -cmd1cmd2, 并且cmd1已经超时(如预期的那样)。但是,根据文档,cmd2也不应该运行。但它仍然毫无例外地运行并正确更新另一行。

4

1 回答 1

2

您没有在连接上运行多个命令,您有两个命令依次运行,一个接一个。当第一个命令超时时,连接上没有其他命令挂起。在第一个命令成功或引发异常之前,您的代码不会提交第二个命令以供执行。

您引用的文档的最后一段应为:在多个 OracleCommand 对象同时使用同一连接的情况下,...

static void Main(string[] args)
{
    using (var conn = new OracleConnection("Pooling=False;...")) // why?
    using (var cmd1 = conn.CreateCommand())
    using (var cmd2 = conn.CreateCommand())
    {
        cmd1.CommandText = "UPDATE employee SET empname = 'temp1' WHERE id = 1";
        cmd2.CommandText = "UPDATE employee SET empname = 'temp2' WHERE id = 2";
        cmd1.CommandTimeout = 30;
        cmd2.CommandTimeout = 30;

        conn.Open();

        // there are no commands on conn yet

        try { cmd1.ExecuteNonQuery(); } // cmd1 is the only command on conn
        catch (OracleException) { } // if timeout, no other command affected

        // cmd1 is no longer on conn

        try { cmd2.ExecuteNonQuery(); } // cmd2 is the only command on conn
        catch (OracleException) { } // if timeout, no other command affected

        // cmd2 is no longer on conn
    }
}
于 2012-11-01T15:12:32.910 回答