有没有办法使用通用 DbCommand 进行异步更新?
当使用通用 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();
}
When using a generic DbCommand to perform an update, it will hang indefinately if the row being updated is locked.
The underlying connection used is is Devart's Oracle provider, Devart.Data.Oracle.OracleConnection
Setting the DbCommand.CommandTimeOut has no effect at all, the update never times out.
DbCommand does not implement BeginExecuteNonQuery, so there seems to be no way to use DbConnection/DbCommand in an asynchronous manner.
I am able to get around this by using Devart's OracleCommand and BeginExecuteQuery, but it does .
Is there a way to do this in a generic way?
Simplified code for the oracle specific logic:
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();
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
遗憾的是,不,ADO.NET 中没有具有异步操作的接口或基类(例如 BeginExecuteNonQuery / EndExecuteNonQuery)。 它们仅出现在极少数 ADO.NET 提供程序实现中。 (SqlClient、Devart Oracle)。
也就是说,如果设置 CommandTimeOut 时没有超时,我认为这是提供程序中的错误。
Sadly, no, there is no interface or base class in ADO.NET that has async operations (e.g. BeginExecuteNonQuery / EndExecuteNonQuery). They're only present in very few ADO.NET provider implementations. (SqlClient, Devart Oracle).
That said, if it doesn't time out when a CommandTimeOut is set, in my opinion that's a bug in the provider.
您可以使用 NOWAIT 选项发出 LOCK TABLE 吗? 如果锁定失败,这将立即将控制权返回给您并出现错误。 例如:
有几种方法可以锁定表。 这里是开发人员的锁定指南部分。 此是 SQL 参考页面对于 LOCK TABLE 命令。
另一种选择是使用 SELECT .. FOR UPDATE NOWAIT 语句来锁定要更新的行。 除了更新语句之外,这两个选项都需要向 Oracle 发出其他命令。
Can you issue a LOCK TABLE with the NOWAIT option? This will return control to you immediately with an error if the lock fails. For example:
There are several ways to lock the table. Here is the developer's guide section on locking. This is the SQL Reference page for the LOCK TABLE command.
Another option is to use the SELECT .. FOR UPDATE NOWAIT statement to lock the rows you will be updating. Both options require additional commands to be issued to Oracle besides your update statement.