row cache lock争用是真实的数据字典缓存争用,非锁故障;需通过v$rowcache或v$active_session_history定位dc_sequences等具体争用项,再调大cache、禁用order、拦截错误登录或错峰ddl。

为什么Sequence会争用
根本不是“Sequence坏了”,而是每次NEXTVAL都要修改数据字典里的seq$表行,并持SSX锁——尤其当CACHE为1或NOCACHE时,所有并发请求全卡在dc_sequences缓存项上。你看到的row cache lock等待,本质是真实元数据争用,不是锁故障。
怎么查清争用的是哪个Sequence
别只看等待事件名,必须定位到具体缓存项:
- 查
v$rowcache里谁的GETMISSES和MODIFICATIONS同时偏高:SELECT parameter, gets, getmisses, modifications FROM v$rowcache WHERE getmisses > 1000 ORDER BY getmisses DESC;
重点关注dc_sequences、dc_users、dc_objects - 用
v$active_session_history反推源头:SELECT p1, COUNT(*) c FROM v$active_session_history WHERE event = 'row cache lock' AND sample_time > SYSDATE - 1/24 GROUP BY p1 ORDER BY c DESC;
拿到高频p1值(比如8),再查对应缓存名:SELECT parameter FROM v$rowcache WHERE cache# = 8;
如何安全调大CACHE值
CACHE是唯一立竿见影的手段,但不能直接ALTER SEQUENCE ... CACHE 1000就完事:
- 执行后旧缓存失效,下次
NEXTVAL可能跳号(比如原剩3个,新缓存从1000起占50个) - 业务若接受跳号(99%主键场景都接受),这是最推荐做法;若严格要求连续,只能停服清空所有缓存再重建
- 避免设过大(如
CACHE 10000):实例崩溃时未用完的缓存永久丢失,跳号幅度变大 - 建议值区间:20–200,参考单次批量插入量(如每批插100条,设
CACHE 100)
Java端别在循环里反复查NEXTVAL
即使Sequence已开缓存,JDBC层写法不当照样拖垮性能:
- 避免for循环中逐条执行
SELECT seq_name.NEXTVAL FROM DUAL——网络往返+Statement解析成本远高于序列本身 - 别用
PreparedStatement包裹NEXTVAL:Oracle不支持参数化序列名,反而多一层解析开销 - Hibernate默认
@GeneratedValue(strategy = GenerationType.SEQUENCE)每条insert都触发一次NEXTVAL查询,应显式配allocationSize = 50且确保sequence定义匹配
RAC环境下ORDER和CACHE要协同调整,否则节点间序列值可能乱序;而开发环境反复DROP TABLE后没重置Sequence,才是ORA-00001冲突的真正起点——这些细节比调参更易被忽略。











