先查DBA_TABLESPACE_USAGE_METRICS中used_percent≥95%确认物理空间告急,再关联V$TRANSACTION与V$SESSION识别USED_UBLK>10000且START_TIME超30分钟的长事务;若used_percent=100%且不降,则大概率被长事务锁死。

怎么确认是真满了,还是被长事务卡住
ORA-30036 报错后别急着加文件。DBA_FREE_SPACE 显示“还有空间”,不代表能分配新 undo 段——undo 段需要连续块,且受未提交事务锁死旧块影响。
先查真实占用率:DBA_TABLESPACE_USAGE_METRICS 是唯一可信指标:
SELECT tablespace_name, used_percent FROM dba_tablespace_usage_metrics WHERE tablespace_name LIKE 'UNDO%';
若 used_percent ≥ 95%,基本可断定物理空间告急;若等于 100% 且持续不降,大概率有长事务卡住。
再查活跃事务是否拖住空间:
SELECT s.sid, s.serial#, s.username, t.used_ublk, t.start_time, sq.sql_text FROM v$transaction t JOIN v$session s ON t.ses_addr = s.saddr LEFT JOIN v$sql sq ON s.sql_id = sq.sql_id ORDER BY t.used_ublk DESC;
-
USED_UBLK > 10000且START_TIME超过 30 分钟 → 高风险长事务 - 注意
sql_text是否为空:空值可能表示已断开连接但事务未清理(ghost transaction)
为什么不能只调大 UNDO_RETENTION
UNDO_RETENTION 是“保留建议值”,不是强制锁定期。当 undo 表空间紧张时,Oracle 会直接覆盖旧 undo 数据来腾出空间——哪怕你设了 24 小时,实际可能只保留 5 分钟。
单纯执行 ALTER SYSTEM SET undo_retention = 3600 不仅无效,还可能加剧问题:
- 它会让 Oracle 更“舍不得”回收旧块,进一步压缩可用连续空间
- 在高并发 DML 场景下,反而加速触发 ORA-30036
- 真正起作用的是物理空间和事务提交节奏,不是这个参数
如何快速扩容而不引发连锁故障
优先启用自动扩展,而不是 RESIZE。文件系统碎片可能导致 RESIZE 失败,而 AUTOEXTEND ON 能动态应对突发增长。
操作前先确认路径权限和磁盘余量:
SELECT file_name, bytes/1024/1024 AS mb, autoextensible FROM dba_data_files WHERE tablespace_name = 'UNDOTBS1';
- 如果
AUTOEXTENSIBLE = 'NO',先执行ALTER DATABASE DATAFILE 'xxx.dbf' AUTOEXTEND ON NEXT 512M MAXSIZE 32G - 新增数据文件更稳妥:
ALTER TABLESPACE UNDOTBS1 ADD DATAFILE '/u01/oradata/db/undotbs02.dbf' SIZE 2G AUTOEXTEND ON NEXT 100M MAXSIZE 8G -
MAXSIZE UNLIMITED在生产环境禁用——填满磁盘比报错更致命
Java 应用层能做什么
ORA-30036 是数据库资源硬耗尽,Java 层无法“修复”,只能规避或降级:
- 批量写入必须分批提交:比如 MyBatis 批量
INSERT或UPDATE,每 1000–5000 行显式commit() - 避免在事务中混入非 DB 操作(如 HTTP 调用、日志刷盘),防止事务意外延长
- 检查是否误用了
@Transactional(propagation = Propagation.REQUIRES_NEW)或PRAGMA AUTONOMOUS_TRANSACTION,导致子事务隐式拉长主事务生命周期 - 应用日志里一旦出现 ORA-30036,应立即触发告警并暂停该批次任务,而不是重试——重试只会加重 undo 压力
最常被忽略的一点:即使数据库侧扩容完成,Java 连接池里仍可能缓存着失败事务的上下文,需主动 close/reconnect 对应连接,否则后续请求仍可能复用异常状态。


















