Oracle19c中PL/SQL的DBMS_LOCK机制疑问:多线程是否重复取P_NUMBER
多线程调用下P_NUMBER的唯一性保障分析
这段代码可以确保多线程调用时不会获取到相同的P_NUMBER,具体分析如下:
核心机制:全局排他锁的串行化控制
代码通过DBMS_LOCK实现了全局排他锁的控制:
DBMS_LOCK.ALLOCATE_UNIQUE('LOCK5', HANDLE)为名为LOCK5的锁生成唯一句柄,所有线程都会请求这同一把锁。DBMS_LOCK.REQUEST(..., DBMS_LOCK.X_MODE)请求排他模式锁,同一时间只有一个线程能成功获取锁,其他线程会阻塞在这一步,直到锁被释放。
锁保护下的原子操作
在持有锁的期间,查询与更新操作是原子性的:
- 通过
SELECT TR into P_NUMBER from T_MONITORING where PROCESS_S=0 and ROWNUM=1获取一条未处理的记录ID。 - 立刻执行
UPDATE T_MONITORING td set td.PROCESS_S=1 where td.TR=P_NUMBER and td.PROCESS_S =0将这条记录标记为已处理。
因为排他锁的存在,这两步操作不会被其他线程打断,确保只有当前线程能拿到这条记录;后续线程再查询时,这条记录已被标记为已处理,不会被重复获取。
潜在性能问题
虽然代码能保证唯一性,但全局排他锁会导致并发性能极低——所有线程必须排队等待同一把锁,1000万条记录的处理速度会被限制在单线程水平。
优化建议:提升并发效率
如果需要更高的并发处理能力,可以去掉全局锁,改用Oracle的FOR UPDATE SKIP LOCKED特性,直接在查询时锁定未处理的记录,让多个线程同时处理不同的记录:
SELECT TR INTO P_NUMBER FROM T_MONITORING WHERE PROCESS_S=0 FOR UPDATE SKIP LOCKED ROWNUM=1; UPDATE T_MONITORING td set td.PROCESS_S=1 where td.TR=P_NUMBER;
这个方式既保证了不会获取重复的P_NUMBER,又能让多个线程并行处理,大幅提升处理速度。
内容的提问来源于stack exchange,提问作者VJS
相关产品推荐
相关产品推荐

