15

一直很痛苦的一件事是当您拥有 PreparedStatement 而不是查询本身时记录 SQL (JDBC) 错误。

您总是会收到以下消息:

2008-10-20 09:19:48,114 ERROR LoggingQueueConsumer-52 [Logger.error:168] Error 
executing SQL: [INSERT INTO private_rooms_bans (room_id, name, user_id, msisdn, 
nickname) VALUES (?, ?, ?, ?, ?) ON DUPLICATE KEY UPDATE room_id = ?, name = ?, 
user_id = ?, msisdn = ?, nickname = ?]

当然,我可以编写一个辅助方法来检索值并用实际值解析/替换问号(如果我没有得到这个问题的结果,可能会走这条路),但我只是想知道是否这个问题之前已经被其他人解决了,和/或是否有任何通用的日志记录助手可以自动为我解决这个问题。

在几个答案后编辑:

到目前为止提供的库似乎适合记录调试语句,这无疑是有用的。但是,我正在寻找一种方法来获取 PreparedStatement 本身(不是某个子类)并在发生错误时记录其 SQL 语句。我不想使用 PreparedStatement 的替代实现来部署生产应用程序。

我想我正在寻找实用程序类,而不是 PreparedStatement 专业化。

谢谢!

4

4 回答 4

6

我尝试了 log4jdbc,它为我完成了这项工作。

安全注意事项:截至 2011 年 8 月的今天,log4jdbc 准备好的语句的记录结果不能安全执行。它们可用于分析,但绝不应反馈到 DBMS。

logjdbc 生成的日志示例

2010/08/12 16:30:56 jdbc.sqlonly org.apache.commons.dbcp.DelegatingPreparedStatement.executeUpdate(DelegatingPreparedStatement.java:105) 8. INSERT INTO A_TABLE (ID_FILE,CODE1,ID_G,ID_SEQUENCE,REF,NAME,BAR ,DRINK_ID,AMOUNT,DESCRIPTION,STATUS,CODE2,REJECT_DESCR,ID_CUST_REJ) 值 (2,'123',1,'2','aa','awe',null,'0123',4317.95,'Rccc',' 0',空,空,空)

该库非常易于设置:


我的HSQLDB配置:

jdbc.url=jdbc:log4jdbc:hsqldb:mem:sample

使用甲骨文

jdbc.url=jdbc:log4jdbc:oracle:thin:@mybdd:1521:smt
jdbc.driverClass=net.sf.log4jdbc.DriverSpy

logback.xml:

<logger name="jdbc.sqlonly" level="DEBUG"/>

太糟糕了,它不在 Maven 存储库中,但仍然有用。
根据我的尝试,如果你设置

你只会得到错误的语句,但是,我不知道这个库是否对性能有影响。

于 2010-08-12T14:49:16.613 回答
3

这是非常依赖数据库的。例如,我知道一些 JDBC 驱动程序(例如 sybase,可能是 ms-sql)通过在服务器上创建一个临时存储过程,然后使用提供的参数调用该过程来处理准备好的语句。因此,完整的 SQL 从未真正从客户端传递。

因此,JDBC API 不会公开您需要的信息。您可能能够将您的语句对象转换为内部驱动程序实现,但可能不会 - 您的应用服务器可能会将语句包装在它自己的实现中。

我认为您可能只需要硬着头皮编写自己的类,将参数插入到占位符 SQL 中。这会很尴尬,因为您不能向 PreparedStatement 询问已设置的参数,因此在将它们传递给语句之前,您必须在帮助对象中记住它们。

在我看来,包装驱动程序实现对象的实用程序库之一是实现您想要实现的目标的最实用方法,但无论哪种方式都会令人不快。

于 2009-06-19T17:01:35.593 回答
3

使用P6Spy:它对 Oracle、Mysql、JNDI、JMX、SpringMaven友好。高度可配置。简单和低级集成 可以打印堆栈跟踪。只能打印繁重的呼叫- 基于时间阈值。

于 2015-08-13T20:49:34.307 回答
0
  1. 如果您使用的是 MySQL,MySQL 连接器的 PreparedStatement.toString()确实包含绑定参数。尽管第三方连接池可能会破坏这一点。

  2. 子类 PreparedStatement 用于在添加参数时构建查询字符串。无法从 PreparedStatement 中提取 SQL,因为它使用已编译的二进制形式。

LoggedPreparedStatement看起来很有希望,尽管我还没有尝试过。

与记录所有查询的代理驱动程序相比,它们的一个优点是您可以在记录查询字符串之前对其进行修改。例如,在 PCI 环境中,您可能想要屏蔽卡号。

于 2009-06-19T15:43:16.060 回答