【问题标题】:How can I capture query sent from Java (tomcat) to an Oracle DB?如何捕获从 Java (tomcat) 发送到 Oracle DB 的查询?
【发布时间】:2021-06-20 07:48:32
【问题描述】:

我有一个由第 3 方编写的应用程序,它使用 Java/Tomcat 与 Oracle 12c (12.2.0.1) DB 通信。在其日志中,它报告“插入表时出错”,但未提供详细信息。在与作者的支持人员交谈时,他们表示这是旧代码,他们无法提供更多细节。他们说应用程序可以更好地支持我们商店不支持的 MSSQL。

我想看看进入 Oracle DB 的插入语句是什么样的,但在 v$sqltext 中找不到它。作为替代方案,我希望找到像 fiddler 这样的工具来查看端口 1521 上的出站流量。

是否有特定工具可以捕获未加密的流量,以便我可以看到发送的“查询”以及从 Oracle 数据库返回的响应?

一般的嗅探器可能会起作用,但它们通常会获得大量无关的流量,并且需要相当多的时间才能找到您想要的东西。

注意:

正如我在 cmets 中提到的,我不是 Tomcat/Java 人。我想我找到了类路径的设置位置。给定下面的windows批处理文件,是不是需要更换bcprov-jdk16-138.jar的“驱动”?

set PROJLIB=..\..
set JAVA_HOME=%PROJLIB%\jdk\

set libDIR=%PROJLIB%\appserver\webapps\receiver\WEB-INF\lib
set consoleDIR=%PROJLIB%\bin\lib

set endorsedLibDir=%PROJLIB%\appserver\endorsed

set CPATH= %consoleDIR%\console.jar;%libDIR%\ebxml.jar;%libDIR%\commons-io-1.1.jar;%libDIR%\bcprov-jdk16-138.jar;%libDIR%\xercesImpl.jar

set CLASSPATH=%CPATH%

set PATH=%JAVA_HOME%\bin;%SystemRoot%;%SystemRoot%\system32

补充说明:

上面的文件叫做setenv.bat。

关于尝试从数据库中捕获 SQL,该应用程序不是 Windows 应用程序,它是一个从网络接受数据并将其写入数据库的应用程序。这使得准确知道何时开始和停止监控变得困难。它似乎连接了很短的时间。它似乎可以读取数据,但不能插入。

【问题讨论】:

  • 监控端口 1521 将完全为零。该端口用于购买侦听器以接收传入的连接请求。时期。句号。一旦侦听器接收到请求,它就会生成一个专用服务器(或定位一个调度程序)并告诉请求客户端通过一个不同的未分配端口与该服务器/调度程序通信。 1521 上的唯一流量是入站连接请求和“在端口 4321 上继续”(或侦听器选择的任何端口)的出站消息。
  • 不是我所希望的。

标签: java oracle tomcat sniffing


【解决方案1】:

假设您使用的是 Oracle JDBC 驱动程序,并且您有能力在某些环境中替换 JDBC 驱动程序以调试问题,Oracle 提供versions of the JDBC driver that can be configured to log 执行的 SQL 语句。

另一种方法是在数据库中创建一个servererror trigger 来记录失败的 SQL 语句。我相信这将要求失败的 SQL 语句格式正确,如果第三方应用程序在动态组装语句时遇到错误,则不能保证。如果该语句从未出现在 v$sql 中,这可能表明它的格式不正确,但值得一试。

如果您获得使用 AWR/ASH 表的许可,您也可以尝试查询 dba_hist_active_sess_history。 Oracle 每秒对活动会话进行采样。如果失败的语句恰好在采样中被捕获,您会在那里看到它。如果这是执行单行插入的典型 OLTP 应用程序,您可能需要运行大量示例才能使用该语句捕获活动会话,但这可能是合理的。

【讨论】:

  • 我可以完全控制计算机。我一般不是 Java 人,也不是 Tomcat 人,所以我不确定在哪里可以找到/替换驱动程序。我希望在客户端/应用程序端做到这一点,而不是在数据库服务器上乱七八糟。我在哪里可以找到有关在哪里查看的文档?
  • @PaulStearns - 您只需要在应用服务器上进行更改。干净的方法是查看为 Tomcat 配置的 classpath,找出 JDBC 驱动程序所在的路径中的哪个位置,并将其替换为调试版本。不太优雅但可能更快的方法是在机器上搜索 JDBC 驱动程序所在的位置并替换它们。
  • 我在原始帖子中添加了一条关于 Java 的注释。如果您有时间,如果您能查看它,我将不胜感激。
  • @PaulStearns - JDBC 驱动程序几乎肯定会在文件名中包含“jdbc”。如果是 Oracle 驱动程序,它会是“ojdbc>.jar”对于过去几个 JDK 版本。在您发布的内容中,我没有看到对 JDBC 驱动程序的引用。
  • OP 错误识别为 jdbc 驱动程序的东西是加密提供程序。 Jdbc 驱动程序应该在 $CATALINA_HOME/lib 下,但开发人员倾向于将它放在他们的 WAR 文件中。
【解决方案2】:

如果您有通过 sqldeveloper 访问数据库的权限......

转到报告选项卡,然后向下钻取数据字典、数据库管理、会话,最后是会话。

在该视图中,查找应用的活动模块并查看 Active SQL 选项卡。 其中之一应该有你的插入语句....

这可能也有帮助... https://docs.oracle.com/cd/E17781_01/server.112/e18804/monitoring.htm#ADMQS252

【讨论】:

  • 我先看这里(虽然我通过工具->监控会话),但我看不到会话。我怀疑它登录,插入并注销。为此,我需要查看过去 10 分钟的历史记录。
  • 好的,试试这个? dba.stackexchange.com/questions/8828/… 只需调整过滤...(用户名、状态等以在失败后立即捕获您需要的内容。)
  • 这种方法的问题是如果insert 有一个解析错误,则不起作用。如果您很幸运并且 insert 仅在例如一个违反约束(即插入错误的值但插入语句是可以的)这有效:select * from gv$sql where lower(SQL_FULLTEXT) like '%insert%my_table%'(将my_table替换为propper表名)
【解决方案3】:

最简单的方法是,如果您可以本地化您的数据库会话(使用gv$session 选择您的连接USERNAME)。

获取连接的SIDSERIAL# 并使用以下语句激活10046 跟踪。 (session_id 的替代 SID 和 serial_num 的 SERIAL#)

EXEC DBMS_MONITOR.session_trace_enable(session_id =>271, serial_num=>46473, binds=>TRUE);

请注意,您需要查询gv$session 和执行DBMS_MONITOR 的权限,因此需要DBA 访问权限才能将它们授予您的用户

检查数据库服务器上trace文件夹中的跟踪文件,跟踪文件的名称如xe_m005_1336.trc

Grep 获取表名,你应该会看到类似这样的东西,我模拟了在表上插入失败my_table

=====================
PARSING IN CURSOR #854854488 len=38 dep=0 uid=104 oct=2 lid=104 tim=380974114197 hv=1259660490 ad='7ff08904d88' sqlid='1ttgvst5j9t6a'
insert into my_table(col1) values(:1 )
END OF STMT
PARSE #854854488:c=0,e=495,p=0,cr=0,cu=0,mis=1,r=0,dep=0,og=1,plh=0,tim=380974114195
=====================
PARSE ERROR #854854488:len=39 dep=0 uid=104 oct=2 lid=104 tim=380974117361 err=904
insert into my_table(col1) values(:1 )

请注意,这是一个异常示例

java.sql.SQLSyntaxErrorException: ORA-00904: "COL1": invalid identifier

所以语句失败并返回 PARSE ERROR

如果由于某些约束 vialotation 导致插入失败,您将看到这样的序列

=====================
PARSING IN CURSOR #715594288 len=37 dep=0 uid=104 oct=2 lid=104 tim=382407621534 hv=3290870806 ad='7ff0032e238' sqlid='17t3q0v22dd0q'
insert into my_table(col) values(:1 )
END OF STMT
PARSE #715594288:c=0,e=245,p=0,cr=0,cu=0,mis=1,r=0,dep=0,og=1,plh=0,tim=382407621532
=====================

游标 id 是 #715594288因此请在跟踪文件中进一步检查此 id

BINDS #715594288:

 Bind#0
  oacdty=02 mxl=22(22) mxlc=00 mal=00 scl=00 pre=00
  oacflg=03 fl2=1000000 frm=01 csi=873 siz=24 off=0
  kxsbbbfp=2aa71a00  bln=22  avl=02  flg=05
  value=7
=====================

这里你可以看到在插入中传递的绑定变量,正是值 = 7 导致了失败。

EXEC #715594288:c=0,e=4614,p=0,cr=7,cu=0,mis=1,r=0,dep=0,og=1,plh=0,tim=382407626259
ERROR #715594288:err=2290 tim=382407626283

语句执行失败,异常如

java.sql.SQLIntegrityConstraintViolationException: ORA-02290: check constraint (XXXX.SYS_C0012357) violated

查看documentation了解更多详情

【讨论】:

  • 虽然 dB 位于 Windows 服务器上,因此我无法轻松使用 grep,但在发布此内容之前,我确实在跟踪文件夹(.trc 文件)上做了一个 findstr(windows grep 等效项)。我搜索了表名,用户名和机器名,没有找到任何引用。我会尽快调查你提到的其他项目。
【解决方案4】:

终极方法是在客户端上跟踪 JDBC 连接。请查看完整文档here

第一步中,您必须在CLASSPATH 上获取logging JDBC 驱动程序。日志记录驱动程序的名称中有一个 suggix _g,例如ojdbc8_g.jar 如果你使用ojdbc8.jar

驱动可以在Oracle安装文件夹jdbc/lib/中找到

进一步您必须定义一个 properties 文件,例如 jdbcLogging.properties,其中包含以下内容

.level=SEVERE
oracle.jdbc.level=ALL
oracle.jdbc.handlers=java.util.logging.ConsoleHandler
java.util.logging.ConsoleHandler.level=FINE
java.util.logging.ConsoleHandler.formatter=java.util.logging.SimpleFormatter

最后当您运行 Java 应用程序时,您必须定义两个属性

 java -Doracle.jdbc.Trace=true -Djava.util.logging.config.file=jdbcLogging.properties ...

这将在错误输出中生成一个跟踪文件,您可以在其中找到已执行的语句。

例子

INFO: DRCP Enabled: false
Mar 23, 2021 10:40:31 PM oracle.jdbc.driver.OracleStatement logSQL
CONFIG: BAB2F1 SQL: insert into my_table(col1) values(?)

【讨论】:

  • 这个方案是在客户端(运行tomcat的服务器)还是DB服务器上实现?
  • @PaulStearns 这是运行 Java 的主机上的 client 配置。
【解决方案5】:

我最终做的是下载 WireShark,一个嗅探器,并监控 TCP/IP 数据包。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-11-14
    • 2011-08-24
    • 1970-01-01
    • 2015-03-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多