为什么此更新会锁定 Oracle 10 中的行?

发布于 2024-09-08 01:46:46 字数 1060 浏览 2 评论 0原文

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

  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 运行它然后它就可以工作(尽管有时它也会锁定)

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

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

Here is the code (with server/passwords etc removed)

  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();

            }
        }

The effect of this code is it never gets past the return statement. No error is returned (even overnight)

I am not a database expert but our hard pressed DBA says that the connection was being locked (or the row possibly...) he killed the locking connection but still when I run the code it locks up.

Am I doing it wrong(tm) with regards to asking Oracle to update a row?

I realise I should be using a parametrised query but I had an issue with that and needed simple things!
If I copy the built command out of the cmd. with the debugger and run it using SQL Developer then it works (though sometimes it locks up too)

I can select from the database at will.

I am not sure if this is a normal thing or something to do with our environment, so any help is gladly accepted!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(9

℉絮湮 2024-09-15 01:46:46

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

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

这可能是您的情况:

  1. 您发出上述更新,但从未提交。
  2. 您看不到自己的更改,因此您重试。现在它挂了。

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

如果您想避免代码挂起,请

SELECT... FOR UPDATE NOWAIT;

在执行 UPDATE 之前执行 a 。如果记录被锁定,则 select 将返回错误,您可以捕获并处理该错误。

让您的 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;

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

Combining @Tony's and @Panagiotis answers, and expanding:

Where do you commit the UPDATE done in this code? Are you sure it's getting done?

Could this be your scenario:

  1. You issue the above UPDATE, but never commit.
  2. You don't see your changes, so you try again. Now it hangs.

The row(s) affected by an UPDATE are locked against further updates until committed or rolled back. If you never explicitly commit or rollback, subsequent updates will hang.

If you want to avoid the hang in your code, then execute a

SELECT... FOR UPDATE NOWAIT;

before you do the UPDATE. If the record is locked, the select will return an error, which you can catch and process.

Have your DBA try this query (Tom Kyte be thanked):

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;

To see all the queued up blocks on sessions.

紫竹語嫣☆ 2024-09-15 01:46:46
  • 找出到底锁定了什么(表、行等)

  • 你能执行以下语句吗
    sqlplus 或 sqldeveloper 使用
    相同的凭据?

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

  • Find out what exactly is locked (table, row, etc)

  • Can you execute the statement from
    sqlplus or sqldeveloper using the
    same credentials?

  • Are any triggers attached to the
    table FOO_ACCESS?

┈┾☆殇 2024-09-15 01:46:46

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

If one session issues this update and doesn't commit or roll back, the row is locked by that session until it does (commit or roll back). Could that be what is happening to you?

守望孤独 2024-09-15 01:46:46

您确定参数 studentID 确实只是一个 ID 吗?如果有人试图注入一段格式错误的 SQL,该怎么办?

一些未经处理的输入完全有可能进入 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 table 查看哪些表被哪些会话锁定。

Are you sure that the parameter studentID is truly just an ID? What if it was a malformed bit of SQL that someone tries to inject?

It's entirely possible that som unsanitized input has made it's way into studentID - and causes your query to do something other than what you expect.

For instance, if studentID = "'; DROP ALL TABLES; --" you may have a problem...

Using string concatentation as a means to create a SQL statement is an unsafe practice - and one that is entirely unecessary. It is quite easy to use parameters in SQL commands in .NET, which makes the SQL less susceptible to injection attacks and also improves their performance (by reducing the need to perform statement parsing).

Here's an example that uses parameters:

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

cmd.ExecuteNonQuery();

Beyond that, you can investigate what is causing your query to perform poorly by using the V$XXX tables in Oracle to explore what is going on. If you think you have a lock, you can query the v$lock table to see which tables are locked by which sessions.

夏日浅笑〃 2024-09-15 01:46:46

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

Have you tried opening the connection before creating the command object?

骄兵必败 2024-09-15 01:46:46

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

Oracle will lock a row if multiple writers try to touch it at the same time. Is some other code trying to modify the row or the table at the same time? Have you perhaps executed a SELECT FOR UPDATE statement in another open connection?

我ぃ本無心為│何有愛 2024-09-15 01:46:46

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

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

cmd.Transaction = transaction

return  cmd.ExecuteNonQuery();
}

Have you tried specifying the isolation mode by creating a transaction e.g.

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

cmd.Transaction = transaction

return  cmd.ExecuteNonQuery();
}
蝶…霜飞 2024-09-15 01:46:46

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

即而不是:

using (..snip...) {

  return  cmd.ExecuteNonQuery();
}

尝试

int rv;
using () {

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

I'm curious about one thing. Can you try changing your return statement so that it's outside the using block?

i.e. instead of:

using (..snip...) {

  return  cmd.ExecuteNonQuery();
}

try

int rv;
using () {

  rv = cmd.ExecuteNonQuery();
}
return rv;
摇划花蜜的午后 2024-09-15 01:46:46

看来问题是我不太了解我的工具。

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

现在已经清除了锁并关闭了 SQL Developer 的所有正在运行的副本,代码就像我第一次发布的那样现在可以工作了。 (唷!)

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

It seems that the problem was me not quite understanding my tools.

I believe that SQL Developer was creating the lock at some point, and then when I ran my web application to update the same row it was being locked. In my frustration and ignorance I force closed SQL Developer leaving a lock stuck in the database, and I was unable to clear it without DBA super powers.

Having now had the lock cleared and closed all running copies of SQL Developer cleanly the code as I first posted it now works. (phew!)

Thanks for all your help, especially the idea of SELECT FOR UPDATE to see if my update is going to be refused before I issue it :)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文