Java中记录PreparedStatements的日志

16

在具有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专业化。
谢谢!

这看起来不错:http://www.ibm.com/developerworks/java/library/j-loggable.html - flash
但是这只适用于调试日志记录,对吧?当您已经执行了一个 PreparedStatement 并且您只想在异常之后记录日志时,我不认为这会适用,对吧?您需要默认启用它,我认为这不是一件好事... - kolrie
我们使用p6spy来记录预处理语句 http://www.p6spy.com/ - SWD
只是提醒一下,他们的网站出现了PHP错误,所以我不得不去他们的SF.net下载页面:http://sourceforge.net/project/showfiles.php?group_id=49288 - kolrie
2
你在使用哪个数据库?我发现MySQL驱动程序在预编译语句中实现了toString方法,该方法包含已设置值的语句。 - Joshua
显示剩余2条评论
4个回答

7

我尝试了 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) VALUES (2,'123',1,'2','aa','awe',null,'0123',4317.95,'Rccc','0',null,null,null)

这个库非常容易设置:


我的配置使用 HSQLDB

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

使用Oracle

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

logback.xml:

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

很遗憾它不在Maven仓库中,但仍然非常有用。
根据我的尝试,如果你设置

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


3
使用P6Spy: 它支持Oracle、Mysql、JNDI、JMX、SpringMaven。高度可配置。 简单且低级的集成。 可以打印堆栈跟踪信息。 可以仅打印基于时间阈值的重要调用

3
这与数据库有很大关系。例如,我了解到一些 JDBC 驱动程序(例如 Sybase,也许是 MS-SQL)通过在服务器上创建一个临时存储过程,然后用提供的参数调用该过程来处理预处理语句。因此,完整的 SQL 实际上从未从客户端传递。
因此,JDBC API 不会公开您需要的信息。您可能能够将语句对象转换为内部驱动程序实现,但可能不行——您的应用服务器可能会将语句包装在自己的实现中。
我认为您可能只需硬着头皮编写自己的类,将参数插入到占位符 SQL 中。这将很棘手,因为您无法向 PreparedStatement 查询设置了哪些参数,因此必须在帮助对象中记住它们,然后将其传递给语句。
在我看来,其中一个实用程序库可以包装您的驱动程序实现对象,是实现您想要完成的目标最实际的方法,但无论如何都不会很愉快。

0
  1. 如果您正在使用MySQL,则MySQL Connector的PreparedStatement.toString() 包括绑定参数。但是第三方连接池可能会破坏这一点。

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

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

与记录所有查询的代理驱动程序相比,这些的一个优点是您可以在记录查询之前修改查询字符串。例如,在PCI环境中,您可能希望掩盖卡号。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接