让我们说我有以下代码:
begin
select ... from T where x = 42; -- (1)
.
.
.
update T ... where x = 42; -- (2)
commit;
end;
我是否正确地说,在执行时间(2)时,从(1)中的T中选择的任何内容可能不再在T中,例如,如果在另一个会话中执行以下操作:
delete from T where x = 42;
如果是这样,我想要发生的是'锁定'T
的select语句,因此无法修改。
我意识到我可以通过以下方式明确地做到这一点:
lock table T in exclusive mode;
但如果T
是一个视图怎么办?我是否必须查看T
视图/子视图的定义以查找它引用的所有表并单独锁定它们,或者我可以执行以下操作:
begin
START_TRANSACTION;
select ... from T where x = 42; -- (1)
.
.
.
update T ... where x = 42; -- (2)
commit;
end;
START_TRANSACTION
确保在事务完成之前锁定所有select语句中引用的所有表?
还是有另一个更好的解决方案吗?如果这很重要,我正在使用Oracle 10g。
答案 0 :(得分:5)
我是否正确地说,到时候(2)执行,无论有什么 从(1)中的T中选择可能不再是T
是
所以你可以通过......来锁定行。
SELECT ...
[INTO ...]
FROM T
WHERE x = 42
FOR UPDATE [NOWAIT];
如果其他人已经锁定了行,您可以选择使用NOWAIT使语句失败。如果没有NOWAIT,语句将暂停,直到它可以锁定该行。
答案 1 :(得分:2)
您需要使用here所示的select ... for update
变体。
你肯定不想要锁定整个表,尽管锁定视图是有效的。来自Oracle docs:
在视图上发出LOCK TABLE语句时,底层基表将被锁定。
然而,这可能是一个性能杀手,而你的DBA 将找到你 - 无处可隐藏: - )
答案 2 :(得分:0)
我很确定交易正是你想要的。该帮助强制执行一系列操作所谓的ACID。