我在使用Oracle更新时遇到问题。对ExecuteNonQuery的调用无限期地挂起。
代码:
using (OracleCommand cmd = new OracleCommand(dbData.SqlCommandStr, conn))
{
foreach (string colName in dbData.Values.Keys)
cmd.Parameters.Add(colName, dbData.Values[colName]);
cmd.CommandTimeout = txTimeout;
int nRowsAffected = cmd.ExecuteNonQuery();
}
CommandTimeout设置为5,参数设置为小整数值。
查询:
UPDATE "BEN"."TABLE03" SET "COLUMN03"=:1,"COLUMN04"=:2 WHERE COLUMN05 > 0
查询从sqlplus快速运行,并且通常从我的代码快速运行,但每隔一段时间它就会永远挂起。
我在v $ locked_object上运行了一个查询,并且有一条记录引用了这个表,但我认为这是未完成的更新。
我想知道两件事:什么可能导致更新挂起?
更重要的是,为什么这里不会抛出异常?我希望通话等待五秒钟,然后超时。
答案 0 :(得分:20)
由于搜索结果中的网页排名,我碰到了这个。
在我的情况下,这是因为我在SqlPlus中执行了一个查询,但是我忘了提交它。在这种情况下,正如文森特所说的那样:该行被锁定在另一个会话中。
提交SqlPlus更新解决了这个问题。
答案 1 :(得分:5)
当简单更新挂起时,通常意味着您被另一个会话阻止。 Oracle不允许多个事务更新行。在事务提交或回滚其修改之前,它将锁定已更新/删除的行。这意味着如果其他会话想要修改相同的行,则必须等待。
如果你不想无限制地挂起,你应该在UPDATE之前选择... FOR UPDATE NOWAIT。
答案 2 :(得分:4)
我遇到了一个类似的问题,这个问题是由一个尚未提交的Sql命令引起的 - 我猜这个程序在某个时刻崩溃了。
以下是我解决问题的方法:
首先,打开SqlPlus并提交修复问题。
接下来,如果发生异常,请更改代码以提交事务或回滚。这将使问题再次发生。
您可以将代码更改为以下内容:
using (OracleTransaction transaction = conn.BeginTransaction())
{
using (OracleCommand cmd = new OracleCommand(dbData.SqlCommandStr, conn))
{
foreach (string colName in dbData.Values.Keys)
cmd.Parameters.Add(colName, dbData.Values[colName]);
cmd.CommandTimeout = txTimeout;
try
{
int nRowsAffected = cmd.ExecuteNonQuery();
transaction.Commit();
}
catch
{
transaction.Rollback();
}
}
}
答案 3 :(得分:2)
您可以通过查询V $ SESSION_WAIT来查看会话正在等待的事件(在识别会话的SID之后,可能通过查看V $ SESSION)。如果事件类似于“入队”,那么您正在等待另一个会话持有的锁定,这在这种情况下看起来似乎是一种可能的解释。
答案 4 :(得分:0)
似乎数据库正在等待提交/回滚,因此它会锁定行。我建议添加
int nRowsAffected = cmd.ExecuteNonQuery();
cmd.Commit();
答案 5 :(得分:0)
我经常遇到这个问题,不仅仅是更新查询(特别是“INSERT INTO ... SELECT FROM”查询)。这是在Oracle 9i上。
我找到了解决方案,所以决定找到这个相关的SO主题: 在连接字符串中,设置:
Pooling=False
在连接字符串中。 完整的工作连接字符串可能如下所示:
DATA SOURCE=k19.MYDOMAIN.com/plldb;PERSIST SECURITY INFO=True;Pooling=False;USER ID=IT;Password=SECRET
警告:将池设置为false将要求您的查询在每次运行时都保护新连接。与ODP.NET可靠的情况相比,频繁运行的查询可能会降低性能。考虑到这个问题,运行速度稍微慢一点就好了。