Oracle 12c独立删除操作为何会获取SSX表锁并引发死锁?
问题分析与解答
为什么会出现SSX表锁和死锁?
首先要明确:Oracle在处理父表(比如你的VERSANDPALETTE或简化测试里的p)的删除/更新操作时,需要校验子表的外键完整性——确保没有子表行引用了要被删除/修改的父表行。
如果子表的外键列没有创建索引,Oracle无法快速定位到子表中对应的引用行,为了避免其他会话在这个过程中插入/修改子表的外键数据(破坏外键约束),它会对子表加SSX表级锁(TM锁模式5)。
在你的双会话场景里:
- 会话1先更新了子表
c的某行(持有该行的行锁),随后尝试删除父表p的对应行,此时需要对子表c加SSX表锁; - 会话2同时更新了子表
c的另一行(持有该行的行锁),也尝试删除父表p的对应行,同样需要对子表c加SSX表锁; - 两个会话都持有对方需要的子表行锁,同时又都在等待对方释放行锁来获取表级SSX锁,最终触发死锁。
为什么单会话操作时看不到mode 5的锁?
这不是锁升级,而是Oracle的锁机制优化:
当同一个会话内操作子表和父表时,Oracle知道当前会话已经持有子表的行锁,不存在跨会话的冲突风险,所以不会显式申请表级的SSX锁——它直接通过已持有的行锁就能保证外键完整性,因此在v$locked_object里看不到mode 5的记录。
只有当多个会话同时操作子表的不同行,再去操作父表时,Oracle才需要通过表级SSX锁来跨会话约束外键操作,此时才会出现mode 5的锁记录。
解决方案
给子表的外键列创建索引即可解决问题:
CREATE INDEX c_index ON c(x);
有了索引后,Oracle可以快速定位子表中引用父表行的记录,只需要对子表的对应行加行锁,不需要再申请表级SSX锁,自然就不会出现死锁了。
内容的提问来源于stack exchange,提问作者Lukas H
相关产品推荐
相关产品推荐

