You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Oracle DB 11.2g中能否模拟PostgreSQL式共享行锁?

能不能在Oracle 11.2g里模拟PostgreSQL那样的共享行锁?

首先直接给结论:Oracle 11.2g本身没有原生支持PostgreSQL那种共享行锁——它的行级锁本质都是排他的(TX锁),也就是说只要一个会话锁住了某行,其他会话要改这行就得等。但别担心,我们可以通过两种靠谱的变通方案来模拟出你要的共享行锁行为:允许多个会话持有同一行的"共享锁"(互相不阻塞),但只要有共享锁存在,任何会话都拿不到排他锁;反过来,如果某行已经被排他锁占了,其他会话连共享锁也拿不到。

方案1:自己搞个锁记录表(灵活可控)

这种方式相当于我们自己在数据库里维护一个锁的状态清单,完全自定义锁的规则:

  • 第一步:先建个锁表,用来记录哪张表的哪一行被什么类型的锁锁住了,还有哪个会话持有的锁:
CREATE TABLE row_locks (
    table_name VARCHAR2(30) NOT NULL,
    row_id VARCHAR2(18) NOT NULL,
    lock_type VARCHAR2(10) NOT NULL CHECK (lock_type IN ('SHARE', 'EXCLUSIVE')),
    session_id NUMBER NOT NULL,
    PRIMARY KEY (table_name, row_id, lock_type)
);
  • 第二步:拿共享锁的逻辑(可以写在存储过程里,或者应用层代码里):
    1. 先查一下目标行有没有被加排他锁——如果有,要么等一会儿,要么直接报错提示"行已被排他锁定"。
    2. 要是没排他锁,就往锁表里插一条SHARE类型的记录(注意要保证这个操作是原子性的,比如先给锁表加个行共享锁,避免多个会话同时操作出问题)。
  • 第三步:拿排他锁的逻辑:
    1. 先查目标行有没有任何锁(不管是共享还是排他)——只要有,就等着或者报错。
    2. 确认没锁之后,插一条EXCLUSIVE类型的记录。
  • 第四步:释放锁:会话结束或者事务提交的时候,记得把对应的锁记录删掉就行。

这个方案的好处是你完全说了算,想加什么规则都可以,但要额外维护这个锁表,还要处理会话突然崩了的情况(比如用定时任务清理超时的锁)。

方案2:用Oracle自带的DBMS_LOCK包(简洁省心)

Oracle有个内置的DBMS_LOCK包,专门用来创建自定义锁,我们可以给每一行生成一个唯一的锁标识,然后用它来模拟共享/排他锁:

  • 拿共享锁:先给目标行生成一个唯一的锁名称(比如'LOCK_' || 'your_table' || '_' || row_id),然后调用DBMS_LOCK.REQUEST(lockhandle, DBMS_LOCK.MODE_SHARE, timeout => -1)——这样多个会话可以同时持有这个共享锁,互相不影响。
  • 拿排他锁:同样生成锁名称,调用DBMS_LOCK.REQUEST(lockhandle, DBMS_LOCK.MODE_XCLUSIVE, timeout => -1)——如果这行已经有共享锁了,这个请求会一直等到共享锁释放;如果已经有排他锁,也会阻塞。
  • 释放锁:事务提交或者回滚的时候,Oracle会自动释放这个锁,或者你也可以手动调用DBMS_LOCK.RELEASE(lockhandle)。

这个方案不用自己维护表,用Oracle原生的机制就行,缺点是锁的名称得保证绝对唯一,不然会搞混不同行的锁。

最后总结一下

Oracle 11.2g确实没有原生的共享行锁,但用上面两种方法,完全能模拟出PostgreSQL那种共享行锁的行为。如果你的锁逻辑比较复杂,选自定义锁表;如果只是简单的共享/排他需求,用DBMS_LOCK更省事。

内容的提问来源于stack exchange,提问作者David Balažic

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.19 10:19:48