事务使用READ COMMITTED隔离
执行这两个语句SELECT * FROM CATS WHERE ID=1 FOR UPDATE SKIP LOCKED
SELECT * FROM CATS WHERE ID=1
第一个查询返回ID 1行。我想知道第二个查询是否总是返回值等于第一个查询的结果?
我的疑虑如下
我已阅读以下问题及相关文章: Force Oracle to return TOP N rows with SKIP LOCKED
如果我理解正确,Oracle首先计算结果集,它会打开游标,然后对于每一行,如果行已被锁定,则跳过该行。如果没有SKIP LOCKED
,则在打开游标时会锁定结果集。
这是对的吗?
如果是,给定READ COMMITTED隔离:
事务T1
执行此语句
SELECT * FROM CATS WHERE ID=1 FOR UPDATE SKIP LOCKED
并发事务T2
更新相同的结果集
UPDATE CATS SET CATS.AGE = 10 WHERE CATS.ID = 1
我想知道如果T2在行被T1锁定之前可以更新一行,则给出以下情况:
有可能吗?
答案 0 :(得分:1)
如果skip locked
成功返回ID = 1
行,则后续查询将始终返回等于第一个查询结果的值。
在select for update skip locked
的情况下,Oracle不首先计算结果集,而是在获取时检查块和行。我将尝试通过编写伪代码来解释它
start select for update skip locked
open cursor, skip_locked_SCN := next SCN;
start fetching
for block in table_data_blocks loop
if block.SCN < skip_locked_SCN then -- unchanged block
for row in block.rows(where id = :id) loop -- filter rows
if row is locked then
-- skip that row
else
add_to_resultset(row);
end if;
end loop;
else -- block has been changed
-- go to undo segment and get previous version
undo_block := get_from_UNDO(block); -- (ORA-01555: snapshot too old may be raised)
for undo_row in undo_block.rows(where id = :id) loop
actual_row = block.rows(where rowid = undo_row.rowid); -- get actual version of appropriate row by rowid
if actual_row is locked then
-- skip that row
else
-- check if data in the row remains unchanged
if actual_row.data = undo_row.data then
add_to_resultset(actual_row);
else
-- data changed, skip that row
end if;
end if;
end loop;
end if;
end loop;