我有一个死锁问题,可以通过更改应用程序逻辑轻松解决,但我的印象是 Oracle 的行为会有所不同,而且死锁永远不会发生。例如我有两张桌子
table1( table1_id (PK), num1, num2);
table2(table2_id(PK), table1_id(FK to table1,indexed), low_cardinality_column, num3, num4);
Table2 也有更新( ) 的行级after update
触发器。table1.num
table1.num1 = table1.num1 + :NEW.num3 where table1.table1_id = :NEW.table1_id
第一个进程执行UPDATE table2 set num3 =1 where low_cardinality_column =:bind_var
(没有索引low_cardinality_column
,通常影响数千条记录)。
第二个进程在一个事务中更新 table2 和 table1
UPDATE table2
SET num4 = :bind_var4
WHERE table2_id = :bind_var_id
RETURNING table1_id INTO :out_var
UPDATE table1
SET num2 = :new_num2_val
WHERE table1_id = :out_var
如果这两个进程碰巧同时运行,Trace 显示它们之间存在相当多的死锁,我对此感到有点困惑。table1
我知道如果第二个过程以相反的顺序更新表( ,然后),那么一定会发生死锁table2
,但在这种特殊情况下,我认为引擎实际上不会开始更新,直到它在每个必须更新的记录上获得 RX 锁(因此一个进程会等待另一个进程完成)。如果不能保证,那么死锁的解释是显而易见的:进程 1 以未定义的顺序锁定记录,进程 2 碰巧更新了table2
尚未锁定的行并尝试更新table1
进程 1 已更新的行。对于 SQLServer I会 100% 肯定是这种情况,但我对 Oracle 还是很陌生......
我想知道是否有人可以澄清这个问题。谢谢你。如果重要的话,我使用 10g。
你是对的:进程 2 从 Table2 的更新开始,但在 Table1 的更新时遇到死锁,因为进程 1 正在更新该行(但尚未提交)。
您认为数据库“知道”它将在进程 2 中遇到死锁并拒绝该事务的假设是错误的。数据库不知道事务中未来的语句,因此它无法避免死锁。