代码之家  ›  专栏  ›  技术社区  ›  Loofer

为什么这个更新会锁定Oracle10中的行?

  •  2
  • Loofer  · 技术社区  · 14 年前

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

      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更新行方面,我是否做得不对(tm)?

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

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

    我不确定这是正常的事情还是与我们的环境有关,所以任何帮助都会被欣然接受!

    9 回复  |  直到 14 年前
        1
  •  2
  •   DCookie    14 年前

    结合@tony's和@panagiotis答案,并扩展:

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

    这是你的场景吗?

    1. 您发出上述更新,但从不提交。
    2. 您看不到更改,请重试。现在它挂起来了。

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

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

    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;
    

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

        2
  •  1
  •   devio    14 年前
    • 找出锁定的确切内容(表、行等)

    • 你能执行这个语句吗 使用 相同的证书?

    • 是否有任何触发器附加到 表foo访问?

        3
  •  1
  •   Tony Andrews    14 年前

    如果有一个会话发出此更新而不提交或回滚,则该行将被该会话锁定,直到它提交或回滚为止。这就是你的遭遇吗?

        4
  •  1
  •   LBushkin    14 年前

    您确定参数 studentID 真的只是一个身份证吗?如果是一个 malformed bit of SQL that someone tries to inject ?

    完全有可能是SOM未初始化的输入使其进入 学究 -并使您的查询执行预期之外的操作。

    例如,如果 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 表以查看哪些表被哪些会话锁定。

        5
  •  1
  •   Gabriel Magana    14 年前

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

        6
  •  1
  •   Panagiotis Kanavos    14 年前

    如果多个编写器同时尝试触摸一行,Oracle将锁定该行。是否有其他代码试图同时修改行或表?您是否在另一个打开的连接中执行了select for update语句?

        7
  •  1
  •   Conrad Frix    14 年前

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

    using(OracleTransaction transaction = oOracleConn.BeginTransaction(IsolationLevel.RepeatableRead)
    {
    
    cmd.Transaction = transaction
    
    return  cmd.ExecuteNonQuery();
    }
    
        8
  •  1
  •   chris    14 年前

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

    即代替:

    using (..snip...) {
    
      return  cmd.ExecuteNonQuery();
    }
    

    尝试

    int rv;
    using () {
    
      rv = cmd.ExecuteNonQuery();
    }
    return rv;
    
        9
  •  0
  •   Loofer    14 年前

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

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

    现在已经清除了锁并关闭了所有运行中的SQL开发人员副本,这段代码在我第一次发布的时候就可以运行了。(呸!)

    感谢您的帮助,尤其是在我发布更新之前选择更新以查看我的更新是否将被拒绝的想法:)