更有效地跟踪Bug——记录带有详细参数值的SQL
李顺利
目录
更有效地跟踪Bug——记录带有详细参数值的SQL. 1
引子... 2
log4jdbc. 3
主页... 3
配置样例... 3
效果... 4
使用评价... 5
jdbcdslog. 6
主页... 6
配置样例... 6
效果... 9
使用评价... 10
jdbcdslog-exp. 11
主页... 11
配置样例... 11
效果... 11
新特性和如何使用... 12
胡言乱语... 14
总结或建议... 14
在实际开发工作中,可能需要很多调试的工作,通过调试,也许能够更好地发现程序的具体问题。
假想下,今天QA同事给你报了一个bug,当然她们不会给出具体的原因,而仅仅是给出Bug导致的果,那么你如何fix 这个 bug了,显然每个人处理问题的方法是不一样的,但是大致会这样: 问QA,为什么会出现这样的Bug啊、在什么时间什么地方出现的…? 过后你可能会装作思考状,良久后说,这不是我们的问题,是部署的问题,是DB的问题…当然你还可以聊聊天了(一般来说QA 都是 MM了^_^)…
当然这不是优秀且富有激情的程序员干的事情(也许你就是这样,不过没关系,也许大家或多或少地时候都在做同样的事情),理想的情况是能够根据QA MM 的叙述,加上查找有用的日志,能够重现并解决Bug,如果可以的话,可以和MM聊聊是如何导致这个Bug的。
在大部分的环境下,我们使用的都是很流行的框架,比如说 Hibernate,在查日志的时候,当然你会关心里面SQL的记录,不过这些SQL也许并没有实际的价值,因为它丢失了很多有用的信息。首先应该知道,如果关心Hibernate 生成的SQL,当然需要开启 Show Sql 功能(<property name="showSql" value="true" />),但是你会发现你开启后,Log记录是类似这样的insert … ? ? ?语句,当然这还是有些实用价值的,不过这些语句只能算SQL的架子,并不是一个完整可以运行的SQL,而且确实更多详细的数据,比如这里的“?”是什么。
假如你关心SQL 里面的问号(?)到底是什么的话,那么请阅读下面的内容?如果你认为这在调试过程中并没有关注过,你可以移步寻找你真正感兴趣的事情,当然还是很欢迎你继续阅读了。
本文介绍的就是这两位主角:log4jdbc和jdbcdslog。参考官方文档(官方文档都很详细并全面),你应该能够傻瓜式地配置起这些Tools,这里我就说说我自己的一些使用建议,并改进增强这些工具的功能。
http://code.google.com/p/log4jdbc/
mysql.database.driver=net.sf.log4jdbc.DriverSpy
mysql.database.url= jdbc:log4jdbc:mysql://127.0.0.1:3306/test?useUnicode=true&amp;characterEncoding=utf-8
(其它log及依赖包的配置请参考官网)
log4jdbc的优点的是配置简单,支持全部的主流数据库,而且log中有原生的sql(可以直接运行的,这个想法也是我想改造jdbcdslog的原因,下文介绍),而且整个project代码写的很优美,不过遗憾的是,目前还不支持 DataSource(XA,Pooling),就因为这点我舍弃了它,现在的项目是Data Source + XA ,真的感觉有点遗憾。不过下载源码你会知道,有份TODO,作者会在下个版本进行实现,希望log4jdbc扩展得越来越实用。官网wiki里有篇文章http://code.google.com/p/log4jdbc/wiki/DataSourceExampleForWebSphere,也是介绍如何能够使用DataSource ,我没有深入研究了,如果有兴趣的同学,可以研究下,再开源出来,相应大家会感谢您的辛苦。
Google code 上面确实有Javaer实现了(google code projcect url: log4jdbc-remix),我拿来用了一下,发现在不改变原配置(log4jdbc)的基础上,是有问题的, 错误的具体issues请见http://code.google.com/p/log4jdbc-remix/issues/detail?id=3,后来也就没有使用了(不过我相信作者肯定是成功改造后才共享出来,可能是一些环境问题导致的这个小小问题)。
(相关的配置相信你完全可以通过官网介绍成功地配置好,如果有少少问题的话,可以参考我使用log4jdbc的一个小Demo,请使用 svn check http://usc.googlecode.com/svn/SSHWithAnnotationDemoUselog4jdbc/ )。
http://code.google.com/p/jdbcdslog/
MySql
mysql.database.driver=org.jdbcdslog.DriverLoggingProxy
mysql.database.url=jdbc\:jdbcdslog\:mysql\://127.0.0.1\:3306/test?useUnicode\=true&amp;characterEncoding\=utf-8;targetDriver\=com.mysql.jdbc.Driver
mysql.database.user=root
mysql.database.password=lishunli
mysql.database.maxActive=100
mysql.database.maxIdle=30
mysql.database.maxWait=500
Spring DI
<jee:jndi-lookup id="mssDataSourceActual" jndi-name="${mss.dataSource.main.jndiName}"/>
<bean id="mssDataSource" class="org.jdbcdslog.ConnectionPoolXADataSourceProxy">
<property name="targetDSDirect" ref="mssDataSourceActual" />
</bean>
(jndi的使用,请google)
Weblogic + Oracle
<jdbc-driver-params>
<url>jdbc:oracle:thin:@10.100.53.85:1521:cmn?targetDS=oracle.jdbc.xa.client.OracleXADataSource</url>
<driver-name>org.jdbcdslog.ConnectionPoolXADataSourceProxy</driver-name>
<properties>
<property>
<name>user</name>
<value>mssapp</value>
</property>
<property>
<name>serverName</name>
<value>10.100.53.85</value>
</property>
<property>
<name>portNumber</name>
<value>1521</value>
</property>
<property>
<name>SID</name>
<value>cmn</value>
</property>
</properties>
<password-encrypted>{3DES}ThgsfHr3yB1bfpnD4u/t3A==</password-encrypted>
</jdbc-driver-params>
JBoss + Oracle
<xa-datasource>
<jndi-name>jdbc/coreDataSource</jndi-name>
<debug>true</debug>
<track-connection-by-tx>true</track-connection-by-tx>
<track-statements>true</track-statements>
<isSameRM-override-value>false</isSameRM-override-value>
<xa-datasource-class>org.jdbcdslog.ConnectionPoolXADataSourceProxy</xa-datasource-class>
<xa-datasource-property name="URL">jdbc:oracle:thin:@10.100.53.85:1521:cmn?targetDS=oracle.jdbc.xa.client.OracleXADataSource</xa-datasource-property>
<xa-datasource-property name="User">report</xa-datasource-property>
<xa-datasource-property name="Password">report</xa-datasource-property>
<min-pool-size>10</min-pool-size>
<max-pool-size>200</max-pool-size>
<exception-sorter-class-name>org.jboss.resource.adapter.jdbc.vendor.OracleExceptionSorter</exception-sorter-class-name>
<no-tx-separate-pools/>
</xa-datasource>
支持DataSource(XA,Pooling)是jdbcdslog最大的亮点,还有一个就是作者真的很用心,wiki(文档)写的太详细了,以至于只要看到这份wiki,就完全能够使用jdbcdslog;而log记录的sql的不友好则是它最大的缺憾(我个人是这样认为的,也行你觉得非常完美),如果能像log4jdbc那样显示完整的SQL,那么 jdbcdslog 就很优秀了。
为了向着我自己完美的目标前进,我自己增强了jdbcdslog,使其满足我(也许还有其他人)的需要。
注:个人觉得不友好的地方是:虽然参数都已经写的很清晰了,但是这个语句并不能地直接使用(拿这个sql在控制台上面直接运行),如果需要的话,可能还需要我们一个一个参数进行替换后才可以使用。
(相关的配置可以参考我使用jdbcdslog的一个小Demo,请使用 svn check http://usc.googlecode.com/svn/SSHWithAnnotationDemo/ )。
当然,这个就是我fork的,主页在 http://code.google.com/p/jdbcdslog-exp/,具体的增强功能和如何使用,可以在这里找到。
这个就不贴了,因为jdbcdslog-exp 并没有修改jdbcdslog的配置,使用它的配置就可以了。不过增强功能的会需要少少配置,下面再说。
增强的效果如下:
和上面的效果进行对照,你会发现我修改了什么(注意红色下划线部分)
有没有发现这个sql是可以直接运行的,而且也去掉了执行时间的日志(复制更加简单,Sql一般很长了,从 “select”再 shift+end 就可以选择一行了),是不是很方便。
1) 可以直接填充SQL语句的参数,当然生成的日志语句是可以直接复制出来使用的,这个在上面的效果图中已经体现;
数据库的不同,生成的SQL会有些不同,比如关键词(特殊字符),在Oracle中有' and & and \r, \n,\t,SQL Server中有', Mysql中有' and " and \ and \r,\n,\t(注:考虑过like语句中的特殊字符,不过jdbcdslog-exp并没有实现,这部分,一则我觉得使用率比较少,一则如果真的有的话,注意下应该也不是那么困难。),再比如日期格式。那么如何更改数据库类型来选择合适的生成语句,请看:
在jdbcdslog.properties文件(这个可以参考原始的文档,或者直接新建 jdbcdslog.properties 配置文件放在 class path 路径下就可以了)中配置
#jdbcdslog driver name.if empty,is oracle(default db)
#you may choose "oracle","mysql" ,"sqlserver" or empty (Case-insensitive and does not need the double quotes)
jdbcdslog.driverName=oracle
2) 可以配置是否显示SQL执行的时间,默认不显示,这个默认选择,也在上面效果图中体现了,当然你可以通过下面的配置显示出来。
同样在jdbcdslog.properties文件中配置
#jdbcdslog will show elapsed time
jdbcdslog.showTime=true
3) Maven的支持
Maven的天下已经或者快要来的,当然要支持了,你可以这样依赖:
<dependency>
<groupId>com.googlecode.usc</groupId>
<artifactId>jdbcdslog</artifactId>
<version>1.0.6.2</version>
</dependency>
jdbcdslog-exp 已经放到Maven中央仓库里了(如何deploy到 maven central repo?请阅读我上篇文章:Maven Artifacts如何部署到仓库),为了名称的一致性,选用了jdbcdslog 作为构建名,而不是jdbcdslog-exp。
或者http://jdbcdslog-exp.googlecode.com/files/jdbcdslog-1.0.6.2.jar通过下载并放到class patch里面即可,更多下载请见http://code.google.com/p/jdbcdslog-exp/downloads/list,包括源代码和Javadoc,当然你可以通过svn checkout下来,自己在继续改进, svn url 为 http://jdbcdslog-exp.googlecode.com/svn/trunk/ 。
实际上,这篇博文早就写了个大概,但是被下面的问题一直耽误着:
我使用的是Weblogic + Oracle(安装在本地其他的机器),使用的是org.jdbcdslog.ConnectionPoolXADataSourceProxy,但是不知为什么,在某些情况下,就会出现weblogic卡着,执行不下去,一段时间后,就会出现超时(Time Out)异常,经过很长时间的调试和查看,可能有两个原因造成的:
1) jdbcdslog(jdbcdslog-exp) 本身的Bug,对处理 datasource 类型没有相应的关闭链接(我猜测);
2) 本地Oracle DB安装有问题,因为我的同事也发生过这样的情况,不过比我少多了。
不过你不用担心,这种情况还是比较少出现的,还不影响正常的使用(开发阶段)的。如果您知道为什么会出现这种情况或者有类似的问题出现,欢迎讨论。谢谢。
1. 如果要使用jdbcdslog 或者 jdbcdslog-exp,请先阅读jdbcdslog’s UserGuide http://code.google.com/p/jdbcdslog/wiki/UserGuide。
2. jdbcdslog 只是一个独立包,需要 slf4j-api 和 slf4j-log4j12 的支持。
3. Log中只需要开 statement的 info,其它的都不需要,如果考虑性能测试的时候,就另当别论了。像这样(log4j.xml):
<!-- logger: jdbcdslog -->
<logger name="org.jdbcdslog.StatementLogger">
<level value="INFO"/>
</logger>
<logger name="org.jdbcdslog.ResultSetLogger">
<level value="OFF"/>
</logger>
<logger name="org.jdbcdslog.SlowQueryLogger">
<level value="OFF"/>
</logger>
<logger name="org.jdbcdslog.ConnectionLogger">
<level value="OFF"/>
</logger>
4. 上面关于JDBC工具的实现使用的是代理,类似AOP思想,都是通过监听(可能说Spy更好一点)数据层, 获取JDBC所带来的数据信息。当然还有很多优秀的工具包能够实现这样的功能,比如 spy6。
5. 当然你如果对Git感兴趣的话,你可以clone 或者 fork git://github.com/usc/jdbcdslog.git (from https://github.com/usc/jdbcdslog)。
6. 如果你有什么问题,非常欢迎通过Email(lishunli.me@gmail.com) 联系我,或者QQ:506817493, 或者微博@李顺利Me(http://weibo.com/lishunli),
亦或者请帮忙在http://code.google.com/p/jdbcdslog-exp/issues/list 里面创建Issues,我会及时处理的,谢谢。
顺利更新于2011年12月5日
博客中的一些下载已经放到了百度云了,请根据需要下载。【点我去百度云下载】
最后弱弱地说一下,如果可以的话,转载请提供出处(
),谢谢。
posted on 2011-12-05 01:04
李顺利 阅读(4661)
评论(6) 编辑 收藏