Oracle中的死锁

时间:2014-03-03 10:09:40

标签: sql oracle database-deadlocks

我在Oracle中运行以下查询时遇到了死锁

update MYTABLE 
   set COLUMN1 = COLUMN1 + 589 
 where COLUMN1 >= 7988 
   and COLUMN1 <= 7988

update MYTABLE 
   set COLUMN1 = COLUMN1 + 660 
 where COLUMN1 >= 7840

当两个查询在两个单独的事务中运行时,我怎么会遇到死锁? 我的观点是,当隔离设置为READCOMMITTED时,第二个查询将等待第一个查询完成其事务吗?

我是否有任何提示可以避免死锁?

注意:COLUMN1不是该表中的PK,但是应用程序确保没有重复项。

2 个答案:

答案 0 :(得分:2)

由于两个窗口都重叠,我认为可能存在问题。 Oracle为这两个查询锁定了相同的块,因此在同时执行时会出现问题。

另外,请检查SO上的answer in this question

通过检查dba_lock表来检查锁是否发生。请参阅文档here

答案 1 :(得分:2)

是的,您提交的这些陈述可能会导致死锁。最简单的方案之一是:

  1. 会话1首先发出update声明;
  2. 会话2发出第二个update声明;
  3. 会话1发出第二个update声明;
  4. 示例:

    -- Session #1 locks a subset of rows
    SQL> update mytable 
            set column1 = column1 + 589 
          where column1 >= 7988 
            and column1 <= 7988;
    
    1 row updated.
    
                                               -- session #2
                                               -- trying to lock subset of rows
                                               -- locked by the first session update
                                              SQL> update mytable 
                                                      set column1 = column1 + 660 
                                                    where column1 >= 7840;
    
    
    -- session #1
    -- trying to lock subset of rows that are locked
    -- by session #2 update, that in turn's
    -- trying to lock the subset of rows 
    -- locked by session #1 update statement
    SQL> update mytable 
            set column1 = column1 + 660 
          where column1 >= 7840;
    
    
                                              -- session #2
                                              -- thus deadlock
                                              update mytable 
                                                  set column1 = column1 + 660 
                                                where column1 >= 7840
                                                                  *
                                              ERROR at line 1:
                            ORA-00060: deadlock detected while waiting for resource
    

    使用update子句构造deletewhere语句时,该语句将成为由两部分组成的语句,包括读取和写入部分。读取部分保留行for update并写一个更改它们。因此,第一个会话的update语句锁定某些数据集以进行更新,更改它们并使其保持锁定状态,直到您发出commitrollback,第二个会话的update语句锁定其部分行,他们第一个会话正试图锁定被第二个数据锁定的那部分数据,从而导致死锁。如果您在一个会话中发出这些更新语句,则应该没有死锁。但是,如果在没有提交或回滚的情况下同时在多个会话中发出这些更新语句,请为ORA-00060异常做好准备。

    每个死锁都伴随着一个警报文件的创建。检查文件以获取有关死锁的更多详细信息。

      

    我是否有任何提示可以避免死锁?

    不,没有这样的暗示。