Oracle 11g Express排他表锁下SELECT不阻塞的原因及实现方法
为什么EXCLUSIVE表锁下SELECT不会挂起?
这是Oracle 多版本读一致性(MVCC) 机制在起作用。当你用LOCK TABLE mytab IN EXCLUSIVE MODE加表级排他锁时,这个锁只会阻止其他会话对表做DML(INSERT/UPDATE/DELETE)或者加冲突的锁,但完全不影响查询操作。
Oracle的查询会直接从undo表空间读取数据的旧版本,不需要等待排他锁释放——这种设计既能保证查询不被阻塞,又能让你看到事务开始前的数据状态,是Oracle平衡并发性能与数据一致性的核心逻辑之一。
怎么让SELECT语句挂起直到锁释放?
如果确实需要让SELECT等待锁释放,可以试试这两种实用方法:
方法一:使用
SELECT ... FOR UPDATE
这个语句会尝试获取查询行的排他锁(如果表被加了全局排他锁,整个表的行锁都无法获取),因此会一直挂起直到锁释放。示例代码:SELECT * FROM mytab FOR UPDATE;要是不想无限等待,还可以加
NOWAIT(直接返回错误)或WAIT n(等待n秒后超时)参数。方法二:设置事务隔离级别为
SERIALIZABLE
Oracle默认隔离级别是READ COMMITTED,而SERIALIZABLE会强制事务看到的数据是事务开始时的快照,若其他事务修改了数据,当前事务的查询就会等待锁释放。操作步骤:-- 先设置隔离级别 SET TRANSACTION ISOLATION LEVEL SERIALIZABLE; -- 再执行查询 SELECT * FROM mytab;这个事务里的所有查询都会遵循该规则,直到事务结束。
关于Oracle 10g的Exclusive table (read)锁
其实Oracle从来没有专门的“Exclusive table (read)”锁——你可能混淆了锁的类型。哪怕在10g里,用LOCK TABLE ... IN EXCLUSIVE MODE也不会阻止SELECT,因为MVCC机制在10g中就已经存在了。
如果你的需求是完全阻止所有读操作,Oracle原生锁机制做不到,毕竟MVCC的设计初衷就是让查询不被阻塞。除非执行DDL操作(比如ALTER TABLE、DROP TABLE),DDL会加SCHEMA级别的排他锁,此时其他会话的查询会暂时挂起直到DDL完成,但这是DDL的附带效果,并非专门的读锁。
内容的提问来源于stack exchange,提问作者user140053

