数据库将通过克服读写冲突(使用锁定)自动找出如何并行处理两个或多个事务(作为可序列化的计划)。默认情况下,它们之间是隔离的。
那么为什么我们还需要使用像
SELECT FOR UPDATE
这样的语句来锁定数据库中的任何数据呢?为什么我们不能在交易块中进行我们想要的任何操作?
Begin transaction
//queries
//commit
End transaction
为什么我们不能在交易区块中进行我们想要的任何事情?
因为在 Oracle 中,读者不会阻止作者。如果您从表中
select
,则不会锁定它并且没有事务。所以,想象一下你这样做:
select col1, col2 into l_col1, l_col2
from table1
where ...;
if (<some logic based on l_col2>) then
update table1 set col2 = something where col1 = l_col1;
end if;
没关系;但如果两个会话同时运行该代码,一个会话可能会更新行之间另一个会话选择并执行其更新 - 导致更新丢失或逻辑不正确,因为状态实际上并不符合预期。
如果你这样做
select ... for update
:
select col1, col2 into l_col1, l_col2
from table
where ...
for update; -- or: for update of col2
if (<some logic based on l_col2>) then
update table1 set col2 = something where col1 = l_col1;
end if;
然后从表中选择的行被第一个会话锁定,因此第二个会话必须等待该事务完成才能获得锁定,并且它将看到该事务的状态第 after
行已应用第一次更新。没有丢失更新,没有混乱。您还可以锁定不想更新的行,如文档所述:
select for update
子句(
SELECT
语句)的FOR UPDATE
语句选择结果集的行并锁定它们。SELECT FOR UPDATE
允许您基于行中的现有值进行更新,因为它确保在您更新这些值之前没有其他用户可以更改这些值。您还可以使用SELECT FOR UPDATE
锁定不想更新的行,如示例 9-6 所示。你可以调整行为:
默认情况下,
SELECT FOR UPDATE
语句会等待,直到获取请求的行锁。要更改此行为,请使用位于光标循环中,那么它还允许您执行以下操作
SELECT FOR UPDATE
语句的NOWAIT
、WAIT
或SKIP LOCKED
子句。有关这些子句的信息,请参阅Oracle 数据库 SQL 语言参考。如果SELECT FOR UPDATE
select for update
当
update table1 set col2 = something where current of <cursor>;
与显式光标关联时,该光标称为
SELECT FOR UPDATE
光标。只有FOR UPDATE
游标可以出现在FOR UPDATE
或CURRENT
语句的UPDATE
OF 子句中。 (DELETE
子句是 SQL 语句CURRENT OF
和WHERE
的UPDATE
子句的 PL/SQL 扩展,将语句限制为游标的当前行。)游标查询选择的行在获取时被锁定。 (但桌子本身没有锁定。)