如果我在oracle中的表上运行SELECT ……. FOR UPDATE
查询,但没有返回任何行,则仍会创建行级锁。例如,如果执行以下查询,则不返回任何记录,因为没有object_key的值,该值在表中具有值“xxx”。
select * from payment_detail where object_key = 'xxx' for update;
但是,执行查询后,在表PAYMENT_DETAIL中创建了一个行级锁定,并通过查询表v$locked_object
进行确认。你能否建议如何在这种情况下创建行级别锁定(当查询没有返回任何记录时)
答案 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>
第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从结构上改变了表格。它还将独占锁定已修改的每一行。如果没有修改任何行,则不会进行行级别锁定,但是表级别锁定仍然存在且不会被释放。它不会被释放,因为在两阶段锁定协议锁定仅在提交或回滚阶段释放。