现大家使用的ibatis,hibernate,spring jdbc的sql日志信息,有一点个缺点是占位符与参数是分开打印的,如果想要拷贝sql至PLSQL Developer客户端直接执行,需要自己拼凑sql。而log4jdbc是在jdbc层的一个日志框架,可以将占位符与参数全部合并在一起显示,方便直接拷贝sql在PLSQL Developer等客户端直接执行,加快调试速度。
一.简单介绍:
1.没有使用log4jdbc前sql显示:
select username,password from bitth_date > ? and age < ? and username = ?
2.使用log4jdbc后sql显示:
select username,password from bitth_date > to_date(‘2010-11-11’,’yyyy-mm-dd’) and age < 20 and username = ‘qq2008’ {executed in 2 msec}
这样就可以直接拷贝上面的sql在PLSQL直接执行. 最后的 {executed in 2 msec} 为SQL执行时间.而如果mysql,日志信息将不会出现 to_date()
二.log4jdbc使用:
1.spring xml配置(拦截需要处理的dataSource连接)
<bean id="log4jdbcInterceptor" class="net.sf.log4jdbc.DataSourceSpyInterceptor" /> <bean id="dataSourceLog4jdbcAutoProxyCreator" class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator"> <property name="interceptorNames"> <list> <value>log4jdbcInterceptor</value> </list> </property> <property name="beanNames"> <list> <value>dataSource</value> </list> </property> </bean>
DataSourceSpyInterceptor是一个拦截器类,扩展主要是使用AOP的方式。具体源码为:
/**实现方法拦截器*/ public class DataSourceSpyInterceptor implements MethodInterceptor { private RdbmsSpecifics rdbmsSpecifics = null; private RdbmsSpecifics getRdbmsSpecifics(Connection conn) { if (this.rdbmsSpecifics == null) this.rdbmsSpecifics = DriverSpy.getRdbmsSpecifics(conn); return this.rdbmsSpecifics; } public Object invoke(MethodInvocation invocation) throws Throwable { Object result = invocation.proceed(); if (SpyLogFactory.getSpyLogDelegator().isJdbcLoggingEnabled() && (result instanceof Connection)) { Connection conn = (Connection)result; return new ConnectionSpy(conn, getRdbmsSpecifics(conn)); } return result; } }
MySql日期处理:
class MySqlRdbmsSpecifics extends RdbmsSpecifics { MySqlRdbmsSpecifics() { super(); } String formatParameterObject(Object object) { if (object instanceof java.sql.Time) { return "'" + new SimpleDateFormat("HH:mm:ss").format(object) + "'"; } else if (object instanceof java.sql.Date) { return "'" + new SimpleDateFormat("yyyy-MM-dd").format(object) + "'"; } else if (object instanceof java.util.Date) // (includes java.sql.Timestamp) { return "'" + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(object) + "'"; } else { return super.formatParameterObject(object); } } }
Oracle日期处理
class OracleRdbmsSpecifics extends RdbmsSpecifics { OracleRdbmsSpecifics() { super(); } String formatParameterObject(Object object) { if (object instanceof Timestamp) { return "to_timestamp('" + new SimpleDateFormat("MM/dd/yyyy HH:mm:ss.SSS").format(object) + "', 'mm/dd/yyyy hh24:mi:ss.ff3')"; } else if (object instanceof Date) { return "to_date('" + new SimpleDateFormat("MM/dd/yyyy HH:mm:ss").format(object) + "', 'mm/dd/yyyy hh24:mi:ss')"; } else { return super.formatParameterObject(object); } } }
2.log4j.properties配置:
log4j.rootLogger=INFO,stdout,R_ERROR log4j.logger.asyncAppenders=INFO,stdout,logfileWarn log4j.appender.stdout=org.apache.log4j.ConsoleAppender log4j.appender.stdout.Target=System.out log4j.appender.stdout.layout=org.apache.log4j.PatternLayout log4j.appender.stdout.layout.ConversionPattern=[%p] [%d{yyyy-MM-dd HH:mm:ss}] [%c:%L] - %m%n #log4jdbc config log4j.logger.jdbc.sqlonly=OFF log4j.logger.jdbc.sqltiming=INFO log4j.logger.jdbc.audit=OFF log4j.logger.jdbc.resultset=OFF log4j.logger.jdbc.connection=OFF #log4jdbc config end log4j.logger.org.springframework.beans.factory.support.DefaultListableBeanFactory=ERROR,logfileWarn log4j.logger.org.springframework.web.servlet.DispatcherServlet=ERROR,logfileWarn log4j.logger.org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping=ERROR,logfileWarn log4j.logger.com.shareinfo=DEBUG,logfileWarn #hibernate log4j.logger.org.hibernate.SQL=DEBUG log4j.logger.org.hibernate.type=ERROR #mybatis log4j.logger.com.ibatis=DEBUG log4j.logger.org.apache.ibatis.jdbc.ScriptRunner=DEBUG log4j.logger.org.mybatis.spring=INFO log4j.logger.org.apache.ibatis=DEBUG,stdout log4j.appender.logfileWarn=org.apache.log4j.DailyRollingFileAppender log4j.appender.logfileWarn.File=${catalina.base}/logs/warn.log log4j.appender.logfileWarn.DatePattern='.'yyyy-MM-dd-HH log4j.appender.logfileWarn.layout=com.netflix.logging.log4jAdapter.NFPatternLayout log4j.appender.logfileWarn.Append=true log4j.appender.logfileWarn.layout.ConversionPattern=[%p -> %c:%L] %d{yyyy-MM-dd HH:mm:ss} %m%n log4j.appender.logfileWarn.Threshold=DEBUG log4j.appender.R_ERROR=org.apache.log4j.DailyRollingFileAppender log4j.appender.R_ERROR.Threshold=ERROR log4j.appender.R_ERROR.File=${catalina.base}/logs/error.log log4j.appender.R_ERROR.Append=true log4j.appender.R_ERROR.DatePattern='.'yyyy-MM-dd log4j.appender.R_ERROR.layout=com.netflix.logging.log4jAdapter.NFPatternLayout log4j.appender.R_ERROR.layout.ConversionPattern=[%p -> %c:%L] %d{yyyy-MM-dd HH:mm:ss} %m%n log4j.logger.java.sql.Connection=DEBUG log4j.logger.java.sql.Statement=DEBUG log4j.logger.java.sql.PreparedStatement=DEBUG log4j.logger.java.sql.ResultSet=DEBUG
(日志信息如果全部为off,log4jdbc将不会生效,因此对性能没有任何影响) log4jdbc需要依赖slf4j日志框架
更多处理及配置属性见附件