在oracle表中的行锁定没有选择任何行

时间:2014-09-04 06:27:01

标签: sql oracle

如果我在oracle中的表上运行SELECT ……. FOR UPDATE查询,但没有返回任何行,则仍会创建行级锁。例如,如果执行以下查询,则不返回任何记录,因为没有object_key的值,该值在表中具有值“xxx”。

select * from payment_detail where object_key = 'xxx' for update;  

但是,执行查询后,在表PAYMENT_DETAIL中创建了一个行级锁定,并通过查询表v$locked_object进行确认。你能否建议如何在这种情况下创建行级别锁定(当查询没有返回任何记录时)

2 个答案:

答案 0 :(得分:3)

3 - ROW_X(SX):行独占表锁

这是一个演示:

SQL> CREATE TABLE t AS
  2    SELECT LEVEL COL
  3    FROM   dual
  4    CONNECT BY LEVEL <= 10;

Table created.

SQL>
SQL> SELECT *
  2  FROM   t
  3  WHERE  col = 20
  4  FOR UPDATE;

no rows selected

SQL>
SQL> SELECT object_id,
  2         session_id,
  3         process,
  4         locked_mode
  5  FROM   v$locked_object;

 OBJECT_ID SESSION_ID PROCESS                  LOCKED_MODE
---------- ---------- ------------------------ -----------
     92549         12 9012:6928                          3

SQL> rollback;

Rollback complete.

SQL> SELECT object_id,
  2         session_id,
  3         process,
  4         locked_mode
  5  FROM   v$locked_object;

no rows selected

SQL>

有关其他会话是否可以使用现有行独占表锁

执行DML的详细信息

第1节:

SQL> SELECT *
  2  FROM   t
  3  WHERE  col = 20
  4  FOR UPDATE;

no rows selected

SQL>
SQL> SELECT object_id,
  2         session_id,
  3         process,
  4         locked_mode
  5  FROM   v$locked_object;

 OBJECT_ID SESSION_ID PROCESS                  LOCKED_MODE
---------- ---------- ------------------------ -----------
     92551        124 8784:7948                          3

会话2:更新表格

SQL> update t set col = 20 where col = 10;

1 row updated.

第1节:

SQL> SELECT object_id,
  2         session_id,
  3         process,
  4         locked_mode
  5  FROM   v$locked_object;

 OBJECT_ID SESSION_ID PROCESS                  LOCKED_MODE
---------- ---------- ------------------------ -----------
     92551          7 8036:1680                          3
     92551        124 8784:7948                          3

会话2:提交问题

SQL> commit;

Commit complete.

SQL>

第1节:

SQL> select * from t;

       COL
----------
         1
         2
         3
         4
         5
         6
         7
         8
         9
        20

10 rows selected.

SQL> SELECT object_id,
  2         session_id,
  3         process,
  4         locked_mode
  5  FROM   v$locked_object;

 OBJECT_ID SESSION_ID PROCESS                  LOCKED_MODE
---------- ---------- ------------------------ -----------
     92551        124 8784:7948                          3

SQL>

因此,session_id 7现在已从锁中释放。您可以看到object_id在所有情况下都锁定了同一个表。

所以,是的,其他会话可以更新,因为您没有锁定任何行进行更新。

但是,如果SELECT..FOR UPDATE返回任何行,那么这些行将被独占锁定,其他会话不能对这些行执行任何DML并将继续等待,直到上一个会话已提交或回滚变化。

希望它有所帮助!

答案 1 :(得分:3)

使用他的例子扩展Lalit Kumar B的答案:

CREATE TABLE t AS
  SELECT LEVEL col
  FROM   dual
  CONNECT BY LEVEL <= 10
/

Table created.

SELECT *
FROM   t
WHERE  col = 20
FOR UPDATE;
/

no rows selected

SELECT xidusn,
       xidslot,
       xidsqn,
       object_id,
       session_id,
       locked_mode
FROM v$locked_object
/

    XIDUSN    XIDSLOT     XIDSQN  OBJECT_ID SESSION_ID LOCKED_MODE
---------- ---------- ---------- ---------- ---------- -----------
         0          0          0     777950        130           3

SELECT sid,
       type,
       id1,
       id2,
       lmode,
       request,
       ctime,
       block
FROM   v$lock
WHERE  sid = 130
/

       SID TYPE        ID1        ID2      LMODE    REQUEST      CTIME      BLOCK
---------- ---- ---------- ---------- ---------- ---------- ---------- ----------
       130 AE          100          0          4          0       2771          0 
       130 TM       777950          0          3          0        582          0

针对v $ locked_object的查询表示该表被锁定在锁定模式3(即行独占模式)。由于XIDUSN,XIDSLOT和XIDSQN均为0,因此表示实际上没有行被锁定。

这可以通过针对v $ lock的查询来确认。忽略AE锁定,表格上有一个TM Lock / Enqueue,以防止在交易过程中对表格进行结构更改。这是锁定模式3(即行独占模式)。但是行级没有TX Locks / Enqueues。

这可以与:

进行比较
ROLLBACK
/

Rollback complete.

SELECT *
FROM   t
WHERE  col = 1
FOR UPDATE;
/
       COL
----------
         1

SELECT xidusn,
       xidslot,
       xidsqn,
       object_id,
       session_id,
       locked_mode
FROM v$locked_object
/

    XIDUSN    XIDSLOT     XIDSQN  OBJECT_ID SESSION_ID LOCKED_MODE
---------- ---------- ---------- ---------- ---------- -----------
         6         31     938022     777950        130           3 

SELECT sid,
       type,
       id1,
       id2,
       lmode,
       request,
       ctime,
       block
FROM   v$lock
WHERE  sid = 130
/

       SID TYPE        ID1        ID2      LMODE    REQUEST      CTIME      BLOCK
---------- ---- ---------- ---------- ---------- ---------- ---------- ----------
       130 AE          100          0          4          0       3315          0 
       130 TM       777950          0          3          0         61          0 
       130 TX       393247     938022          6          0         61          0

针对v $ locked_object的查询再次表明该表被锁定在锁定模式3(即行独占模式)。但是,由于XIDUSN,XIDSLOT和XIDSQN都是非0,这表示行也被锁定。

这可以通过针对v $ lock的查询来确认。同样,在表上存在TM Lock / Enqueue,以防止在锁定模式3(即行独占模式)中的事务期间对表的结构改变。在锁定模式6(独占模式)中还有TX锁定/队列,因此返回更新的行不能被其他用户修改。

总之。一旦发出DML以修改表中的行,或发出SELECT ... FOR UPDATE表示您有意修改表中的行,Oracle将首先在表级别采用行独占模式锁定以确保不发布DDL从结构上改变了表格。它还将独占锁定已修改的每一行。如果没有修改任何行,则不会进行行级别锁定,但是表级别锁定仍然存在且不会被释放。它不会被释放,因为在两阶段锁定协议锁定仅在提交或回滚阶段释放。