DBMS_SESSION.SET_SQL_TRACE仅在当前会话生效,需在获取Connection后、执行SQL前用createStatement()立即调用BEGIN...END;块开启,并显式关闭;trace文件由Oracle实例参数决定,JDBC无法控制路径与命名。
DBMS_SESSION.SET_SQL_TRACE 要在会话级生效,不是全局开关
这个过程本质是让 oracle 在当前数据库会话中开启 sql 语句级追踪(即生成 trace 文件),它不改变实例配置,也不影响其他连接。关键点在于:jdbc 建立的连接必须「保持活跃」且「未被连接池回收」,否则你刚设完 trace,连接就被归还池里,下次取到的可能是另一个物理会话。
- 必须在获取
Connection后、执行业务 SQL 前立即调用EXECUTE IMMEDIATE 'BEGIN DBMS_SESSION.SET_SQL_TRACE(TRUE); END;' - 不能依赖连接池的“初始化 SQL”配置(如 HikariCP 的
connection-init-sql),因为某些驱动或池实现会在连接复用时跳过该逻辑 - 如果用 Spring
@Transactional,注意事务可能跨多个连接(如传播行为为 REQUIRES_NEW),trace 只对当前连接有效
JDBC 执行 SET_SQL_TRACE 需绕过 PreparedStatement 缓存
Oracle JDBC 驱动对以 BEGIN ... END; 形式提交的匿名 PL/SQL 块,默认会走 PreparedStatement 流程,而部分老版本驱动(如 ojdbc6)会对这类语句做缓存或语法重写,导致 DBMS_SESSION.SET_SQL_TRACE 不被执行或报 ORA-06550 错误。
- 务必使用
Connection.createStatement()+executeUpdate(),而非prepareStatement() - 语句字符串必须是完整可执行块:
"BEGIN DBMS_SESSION.SET_SQL_TRACE(TRUE); END;",不能省略BEGIN/END - 避免拼接变量——哪怕只是开关布尔值,也别用参数占位符,PL/SQL 块内不支持绑定变量传入过程调用上下文
Trace 文件位置和命名依赖 Oracle 实例参数,不是 JDBC 控制
JDBC 本身不决定 trace 文件写在哪、叫什么名。实际路径由数据库侧的 user_dump_dest(11g)或 diagnostic_dest(12c+)决定,文件名含 PID 和会话标识,例如 orcl_ora_12345.trc。你无法通过 JDBC 指定文件名或目录。
- 应用日志里看不到 trace 内容,只能去数据库服务器上找对应文件
- 确认当前会话 PID:执行
SELECT SYS_CONTEXT('USERENV', 'SID') FROM DUAL,再查V$PROCESS关联 SPID - 若用容器化部署(如 Oracle XE Docker),需提前挂载
diagnostic_dest对应路径,否则 trace 文件可能写在不可见的临时层里
关闭 trace 必须显式调用,不能靠连接关闭自动清理
Oracle 不会在 JDBC Connection.close() 时自动关闭 SQL Trace。一旦开启,该会话后续所有 SQL(包括连接池后台校验语句)都会被 trace,直到显式关闭或会话断开。长时间开着会导致 trace 文件暴涨,甚至撑爆磁盘。
- 务必在业务逻辑结束后执行:
"BEGIN DBMS_SESSION.SET_SQL_TRACE(FALSE); END;" - 推荐放在
try-with-resources的 finally 块,或 Spring@AfterReturning/@AfterThrowing切面中统一处理 - 如果应用异常崩溃或连接被强制 kill,trace 会随会话终止而停止,但已生成的 trace 文件不会自动清理
最常被忽略的是连接生命周期和 trace 开关的配对——开了没关、关了又开、在错误会话上开,这三类问题占排查耗时的八成。别信“连上了就 trace”,得盯住那个具体的 Connection 实例。










