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

如何合理配置Oracle JDBC驱动日志以记录所有增删改查SQL语句

Oracle JDBC日志无法正常捕获update/insert语句问题

我希望记录应用程序发起的所有SQL语句,以便精准掌握其运行行为。我已参照相关方案为Oracle配置了Java Util Logging,尝试从最底层捕获相关日志。
我的应用使用Hibernate(当前版本为3.2.3.ga)。
当我在logging.properties中配置oracle.jdbc.level=CONFIG或oracle.jdbc.level=FINE时,日志量级比较合理,但完全看不到应用发起的update语句,只能看到select和delete语句,示例如下:

CONFIG oracle.jdbc: 73FCEAC9 SQL: select <REDACTED FOR STACK OVERFLOW>

当我在logging.properties中配置oracle.jdbc.level=FINEST时,可以看到update和insert语句,但日志量级过大完全不具备实用性。看起来这些语句是被FINEST级别下「记录内部方法调用」的逻辑捕获的,单条update语句会在日志中出现数十次,示例如下:

FINEST oracle.jdbc: 212E0078 Enter: "update <REDACTED FOR STACK OVERFLOW>" 
FINEST oracle.jdbc: 212E0078 Enter: "update <REDACTED FOR STACK OVERFLOW>", -1, -1 
FINEST oracle.jdbc: 212E0078 Enter: "update <REDACTED FOR STACK OVERFLOW>", "[ {result_set_type=-1}  {use_long_fetch=false}  {result_set_concurrency=-1} ]" 
FINEST oracle.jdbc: 212E0078 Enter: "update <REDACTED FOR STACK OVERFLOW>", "[ {result_set_type=-1}  {use_long_fetch=false}  {result_set_concurrency=-1} ]" 
FINEST oracle.jdbc: 212E0078 Enter: void 
FINEST oracle.jdbc: 212E0078 Return: void 
FINEST oracle.jdbc: 212E0078 Exit: [0.012976 ms] 
FINEST oracle.jdbc: 2C5FB90F Enter: oracle.jdbc.driver.T4CConnection@212e0078, "update <REDACTED FOR STACK OVERFLOW>", "[ {result_set_type=-1}  {use_long_fetch=false}  {result_set_concurrency=-1} ]" 
FINEST oracle.jdbc:          Enter: oracle.jdbc.driver.T4CConnection@212e0078 
FINEST oracle.jdbc:          Return: void 
FINEST oracle.jdbc:          Exit: [0.012198 ms] 
FINEST oracle.jdbc:          Enter: oracle.jdbc.driver.T4CConnection@212e0078, "[ {result_set_type=-1}  {use_long_fetch=false}  {result_set_concurrency=-1} ]" 
FINEST oracle.jdbc:          Enter: oracle.jdbc.driver.T4CPreparedStatement@9887002 
FINEST oracle.jdbc:          Return: void 
FINEST oracle.jdbc:          Exit: [0.016657 ms] 

我原本以为oracle.jdbc.level=FINE配置可以捕获update语句,因为官方文档说明该级别会「记录所有公共方法的出入栈,提供JDBC操作的详细追踪」,但实际该级别记录的内容和oracle.jdbc.level=CONFIG几乎完全一致。
我已尝试以下版本的Oracle驱动(Gradle依赖格式):

compile group: 'com.oracle.database.jdbc.debug', name: 'ojdbc8_g', version: '12.2.0.1'
compile group: 'com.oracle.database.jdbc.debug', name: 'ojdbc8_g', version: '21.3.0.0'

有没有办法配置Oracle驱动,使其只记录所有select、update、insert、delete语句,不产生多余日志?我还尝试过配置oracle.sql.level=FINE和oracle.level=FINER,但在这些级别及更粗的日志级别下,都没有输出和update相关的有效日志。

更新

我安装了p6spy,但它同样无法记录insert和update语句。不过有相关方案通过启用批处理日志功能解决了这个问题。本次遇到的Oracle驱动日志问题是否是同样的原因,即CONFIG级别不会记录批量更新语句?


解决方案

你的猜测是正确的,该问题的核心原因是Oracle JDBC驱动对批量执行的DML语句和单条执行语句的日志分级策略不同:单条执行的select、delete语句默认会在CONFIG/FINE级别输出,而批量执行的insert、update语句默认仅在FINEST级别输出,同时FINEST级别会默认打印所有内部方法的出入栈日志,导致日志冗余。
可通过以下两种方案实现仅输出所有SQL语句、无冗余日志的需求:

方案1:调整Oracle JDBC驱动日志配置,添加日志过滤

无需修改应用代码,仅调整logging.properties配置即可:

# 基础日志级别,保证常规单条SQL正常输出
oracle.jdbc.level=FINE
# 仅针对PreparedStatement类开启FINEST级别,避免全局开启产生大量冗余日志
oracle.jdbc.driver.OraclePreparedStatement.level=FINEST
# 配置日志过滤器,仅保留包含SQL关键字的日志,过滤掉方法出入栈的Enter/Return/Exit日志
oracle.jdbc.driver.OraclePreparedStatement.filter=java.util.logging.Filter \
  public boolean isLoggable(LogRecord record) { \
    String msg = record.getMessage(); \
    return msg != null && (msg.contains("insert") || msg.contains("update") || msg.contains("delete") || msg.contains("select")); \
  }
# 开启批量执行日志输出
oracle.jdbc.batchLog=true

如果你的项目使用SLF4J桥接JUL,也可以直接在日志框架(Logback/Log4j)的配置中添加过滤规则,实现相同效果,配置更灵活。

方案2:调整p6spy配置输出批量SQL

你之前使用p6spy无法捕获insert/update就是因为没有开启批量日志,修改spy.properties配置即可:

# 移除batch类别的日志排除
excludecategories=info,debug,result,resultset
# 显式包含批量执行日志
includecategories=batch
# 可选:配置为单行输出,日志可读性更高
logMessageFormat=com.p6spy.engine.spy.appender.SingleLineFormat

该方案无需调整Oracle驱动本身的日志配置,输出的SQL格式更统一,还可以直接打印SQL的执行耗时、参数替换后的完整语句,实用性更高。


内容的提问来源于stack exchange,提问作者Kaypro II

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.30 22:36:03