【问题标题】:Why does this update lock the row in Oracle 10?为什么此更新会锁定 Oracle 10 中的行?
【发布时间】:2011-03-12 09:05:29
【问题描述】:

这是代码(删除了服务器/密码等)

  public int SetUploadedInESIDatabase(string ID)
        {
            using (var oOracleConn = new OracleConnection())
            {
                oOracleConn.ConnectionString =
                    @"Data Source=(DESCRIPTION=(ADDRESS_LIST=(ADDRESS=(PROTOCOL=TCP)(HOST=<ip>)(PORT=1521)))(CONNECT_DATA=(SERVER=DEDICATED)(SERVICE_NAME=<dbname>)));User Id=<user>;Password=<password>;";
                var cmd =
                    new OracleCommand(
                        "UPDATE FOO_ACCESS SET PIMAGE ='-1' WHERE CODE= '" + ID + "'", oOracleConn);

                oOracleConn.Open();



                return  cmd.ExecuteNonQuery();

            }
        }

这段代码的效果是它永远不会超过 return 语句。没有返回错误(即使是一夜之间)

我不是数据库专家,但我们的 DBA 说连接被锁定(或者行可能......)他杀死了锁定连接,但是当我运行代码时它仍然被锁定。

关于要求 Oracle 更新一行,我做错了吗?

我意识到我应该使用参数化查询,但我遇到了问题,需要一些简单的东西! 如果我从 cmd 中复制构建的命令。使用调试器并使用 SQL Developer 运行它然后它可以工作(尽管有时它也会锁定)

我可以随意从数据库中选择。

我不确定这是正常现象还是与我们的环境有关,因此我们很乐意接受任何帮助!

【问题讨论】:

  • 哇,这真的是 C# 中的 Oracle 连接字符串的样子吗?相比之下,它实际上使 Oracle 的 Java 连接字符串看起来不错!
  • @ R. Bemrose:如果您不使用 Oracle TNSNAMES.ORA 文件为服务器提供友好名称,那么这只是连接字符串的样子。否则,使用 TNSNAMES 看起来会更好:Data Source=ServerName; User Id=user; Password=pw.
  • @R. Bemrose:Oracle 支持不同的连接字符串格式connectionstrings.com/oracle#p12
  • @LBushkin:我知道这就是 tnsnames.ora 的样子,我只是从未见过一种编程语言将它用于驱动程序连接字符串而不是它自己的格式。
  • @R.Bemrose:如果您愿意,可以指定连接字符串到 SQL*Plus。它与 C# 无关。

标签: c# oracle database-connection


【解决方案1】:
  • 找出锁定的具体内容(表、行等)

  • 你能执行从 使用 sqlplus 或 sqldeveloper 相同的凭据?

  • 是否有任何触发器附加到 表 FOO_ACCESS?

【讨论】:

  • 谢谢。我可以从 sqldeveloper 运行查询,它有时 工作...在代码中它从不 工作。剩下的我会去找有用的 DBA :)
【解决方案2】:

您确定参数studentID 真的只是一个ID 吗?如果是malformed bit of SQL that someone tries to inject,会怎样?

som 未经处理的输入完全有可能进入studentID - 并导致您的查询执行与您预期不同的操作。

例如,如果studentID = "'; DROP ALL TABLES; --" 你可能有问题...

使用字符串连接作为创建 SQL 语句的一种方法是一种不安全的做法,而且完全没有必要。在 .NET 中使用 SQL 命令中的参数非常容易,这使得 SQL 不易受到注入攻击并提高了性能(通过减少执行语句解析的需要)。

这是一个使用参数的例子:

var cmd = new OracleCommand( 
       "UPDATE FOO_ACCESS SET PIMAGE = '-1' WHERE CODE = :code", oracleConn );
cmd.Parametes.Add( ":code", studentID );

cmd.ExecuteNonQuery();

除此之外,您还可以通过使用 Oracle 中的 V$XXX 表来调查正在发生的事情,从而调查导致查询执行不佳的原因。如果你认为你有一个锁,你可以查询v$lock 表来查看哪些表被哪些会话锁定。

【讨论】:

  • 我目前正在开发中,所以没有野人可以尝试得到我。我当然只会在野外放出参数化的东西! (正如我在我的问题中所说:)我没有看到 v$lock 表的权限,所以回到 dba 吧!
  • 我现在已经参数化我的查询了,因此我无法将生成的sql命令复制并粘贴到另一个程序中进行测试。
【解决方案3】:

如果一个会话发布此更新并且没有提交或回滚,则该行将被该会话锁定,直到它执行(提交或回滚)。这可能是发生在你身上的事情吗?

【讨论】:

  • 这听起来很可能,但是如果 UPDATE 失败,它为什么不提交或回滚...我可以暗​​示我希望它在某个时候停止尝试吗?
【解决方案4】:

您是否尝试在创建命令对象之前打开连接?

【讨论】:

  • 这似乎没有效果。不过谢谢:)
【解决方案5】:

如果多个写入者试图同时触摸一行,Oracle 将锁定该行。是否有其他代码试图同时修改行或表?您是否可能在另一个打开的连接中执行了 SELECT FOR UPDATE 语句?

【讨论】:

  • UPDATE 是我运行的唯一 SQL...我不知道 SELECT FOR UPDATE ...这是我应该做的事情吗?
【解决方案6】:

您是否尝试过通过创建事务来指定隔离模式,例如

using(OracleTransaction transaction = oOracleConn.BeginTransaction(IsolationLevel.RepeatableRead)
{

cmd.Transaction = transaction

return  cmd.ExecuteNonQuery();
}

【讨论】:

  • 不... 是RepeatableRead 我想要什么?看看枚举可能是 .Chaos :D
【解决方案7】:

我对一件事感到好奇。您可以尝试更改您的 return 语句,使其位于 using 块之外吗?

即而不是:

using (..snip...) {

  return  cmd.ExecuteNonQuery();
}

试试

int rv;
using () {

  rv = cmd.ExecuteNonQuery();
}
return rv;

【讨论】:

  • 它永远不会到达 return 语句,停留在 cmd.ExecuteNonQuery() 阶段。
  • 如果你用一个简单的选择替换 sql 会发生什么 - 即从 foo_access 中选择 count(*)?您没有使用 tnsnames.ora 来解析连接是否有原因?
  • 选择工作正常。我没有使用 tnsnames.ora,因为我对 Oracle 一无所知,而 dba 对编程一无所知,而且我正在做任何有效或似乎有效的事情:O
【解决方案8】:

结合@Tony 和@Panagiotis 的答案,并扩展:

您在哪里提交在此代码中完成的更新?确定完成了吗?

这可能是你的场景:

  1. 您发出上述更新,但从未提交。
  2. 您没有看到您的更改,因此您再试一次。现在它挂起。

受 UPDATE 影响的行被锁定以防止进一步的更新,直到提交或回滚。如果您从未明确提交或回滚,后续更新将挂起。

如果您想避免代码中的挂起,请执行

SELECT... FOR UPDATE NOWAIT;

在进行更新之前。如果记录被锁定,则选择将返回一个错误,您可以捕获并处理该错误。

让您的 DBA 试试这个查询(感谢 Tom Kyte):

select
      (select username from v$session where sid=a.sid) blocker,
       a.sid,
      ' is blocking ',
       (select username from v$session where sid=b.sid) blockee,
           b.sid
  from v$lock a join v$lock b on (a.id1 = b.id1 and a.id2 = b.id2)
 where a.block = 1
   and b.request > 0;

查看会话中所有排队的块。

【讨论】:

  • 谢谢。我发现了问题(请参阅我在其他地方的“答案”),但是如果无法更新行,这种方法会出错,这样你就可以得到 cookie :)
【解决方案9】:

问题似乎是我不太了解我的工具。

我相信 SQL Developer 在某个时候创建​​了锁,然后当我运行我的 Web 应用程序更新同一行时,它被锁定了。在我的挫折和无知中,我强制关闭 SQL Developer,留下一个锁在数据库中,如果没有 DBA 超能力,我无法清除它。

现在已经清除了锁并干净地关闭了 SQL Developer 的所有运行副本,我第一次发布的代码现在可以工作了。 (呼!)

感谢您的所有帮助,尤其是 SELECT FOR UPDATE 的想法,以便在发布之前查看我的更新是否会被拒绝 :)

【讨论】:

  • 在 sqldeveloper 中进行更新时,需要显式提交事务。有一个自动提交的设置,但如果你打开它,我保证有一天你会后悔的。
猜你喜欢
  • 2015-12-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-04-28
  • 2022-01-04
  • 2011-11-23
  • 2020-07-26
  • 2021-07-27
相关资源
最近更新 更多