Java日志框架——查看“完整的执行的SQL语句”
2015-08-15 16:10
661 查看
项目开发中,在调试的时候,经常会有查看“完整的执行的SQL语句”的需求。
假如我们采用"SLF4J+Logback"的日志框架解决方案,那么该如何配置Logback,使得能够记录“完整的执行的SQL语句”呢?
(假定通过"logback.xml"文件进行Logback配置)
首先有三点需要注意:
1)除非数据库管理模块自身(比如"mysql:mysql-connector-java")包含有记录“完整的执行的SQL语句”的日志操作语句,否则,我们再怎么配置Logback也无济于事。
2)数据库管理模块有可能不是使用SLF4J作为日志框架,此时需要"jcl-over-slf4j","log4j-over-slf4j","jul-to-slf4j"等日志框架桥接器。可以通过数据库管理模块的pom.xml中声明的日志框架依赖,来确定数据库管理模块所使用的日志框架。不过有个特殊情况,当数据库管理模块使用"Java Logging API"时,无需在pom.xml中声明依赖。因此,我们在搭建实验环境的时候总是添加"jul-to-slf4j"这个日志框架桥接器,并且修改"JDK_HOME/jre/lib/logging.properties"文件中的handlers参数值为"org.slf4j.bridge.SLF4JBridgeHandler"
3)在搭建实验环境,配置"logback.xml"文件的时候,为了排除“由于数据库管理模块的日志记录请求的Level值小于相应Logger实例的Level值,不能达到记录‘完整的执行的SQL语句’的目标”的干扰因素,配置<root>标签中的level值为"all"。
实验环境中的"logback.xml"文件内容如下:
接下来分别介绍4种场景下的Logback配置方案。
一、直接使用"mysql:mysql-connector-java"
在本场景中,查询SQL语句的时候,直接使用"mysql:mysql-connector-java"。查看"mysql:mysql-connector-java"的pom.xml文件,可以发现没有声明对任何日志框架的依赖,但还是有可能使用"Java Logging API"这个日志框架。
接下来搭建一个实验环境进行实验。
1、pom.xml
2、logback.xml
见“三点注意”中的logback.xml配置。
3、Java代码
4、运行结果
如图1,通过实验可以得出结论:在本场景中,无论如何配置"logback.xml",都不能达到记录“完整的执行的SQL语句”的目标。
图1
二、使用"com.googlecode.log4jdbc:log4jdbc"[1]
在本场景中,查询SQL语句的时候,使用"com.googlecode.log4jdbc:log4jdbc","com.googlecode.log4jdbc:log4jdbc"是一个中间层,底层还是使用"mysql:mysql-connector-java"。查看"com.googlecode.log4jdbc:log4jdbc"的pom.xml,可以发现依赖"org.slf4j:slf4j-api",即它使用SLF4J作为日志框架。
接下来搭建一个实验环境进行实验。
1、pom.xml
2、logback.xml
见“三点注意”中的logback.xml配置。
3、Java代码
4、运行结果
如图2,通过实验可以得出结论:在本场景下,能够达到记录“完整的执行的SQL语句”的目标。
图2
详细分析运行结果,可以发现名称为"jdbc.sqlonly"和"jdbc.sqltiming"的Logger实例能够记录“完整的执行的SQL语句”。因此,我们应该在"logback.xml"中配置这两个Logger实例相应的<logger>标签,将level值设为合适的值,而将<root>标签的level值从"all"改为合适的"非all"值,因为如果Logger实例的Level过低,在项目运行中会有太多有效的日志记录请求,影响项目运行性能。
修改后"logback.xml"内容如下:
三、使用"org.springframework:spring-jdbc"
在本场景中,查询SQL语句的时候,使用"org.springframework:spring-jdbc","org.springframework:spring-jdbc"是一个中间层,底层还是使用"mysql:mysql-connector-java"。查看"org.springframework:spring-jdbc"的pom.xml,可以发现它递归依赖"commons-logging:commons-logging",即它使用JCL作为日志框架,因而我们需要"jcl-over-slf4j"这个日志框架桥接器,并且需要在包含"org.springframework:spring-jdbc"依赖的时候,通过<exclusion>标签排除掉"commons-logging:commons-logging"依赖。
本场景中还需要有"com.mchange:c3p0"依赖,查看它的pom.xml,可以发现没有对日志框架的依赖,但是它很有可能选用"Java Logging API"作为日志框架。
接下来搭建一个实验环境进行实验。
1、pom.xml
2、logback.xml
见“三点注意”中的logback.xml配置。
3、Java代码
4、运行结果
如图3,通过实验得出结论:能够达到记录“完整的执行的SQL语句”的目标。
图3
详细分析运行结果,可以发现名称为"org.springframework.jdbc.core.StatementCreatorUtils"的Logger实例能够记录“完整的执行的SQL语句”。因此,我们应该在“logback.xml”中配置这个Logger实例相应的<logger>标签,将level值设为合适的值,而将<root>标签的level值从"all"改为合适的"非all"值,因为如果Logger实例的Level过低,在项目运行中会有太多有效的日志记录请求,影响项目运行性能。
修改后“logback.xml”内容如下:
四、使用Mybatis
在本场景中,查询SQL语句的时候,使用“org.mybatis:mybatis","org.mybatis:mybatis"是一个中间层,底层还是使用"mysql:mysql-connector-java"。根据文章《Java日志框架——Mybatis选用的日志框架解决方案》,"org.mybatis:mybatis"动态确定选用的第三方日志框架,再结合"org.mybatis:mybatis"的pom.xml文件中的对日志框架依赖的"optional"属性值,可以知道,我们只要在项目中加入对SLF4J的依赖,就可以令mybatis使用SLF4J日志框架。
接下来搭建一个实验环境进行实验。
1、pom.xml
2、logback.xml
见“三点注意”中的logback.xml配置。
3、Java代码
4、运行结果
如图4,通过实验得到结论:能够达到记录“完整的执行的SQL语句”的目标。
图4
详细分析运行结果,可以发现名称为"Activity.updateActivity"的Logger实例能够记录“完整的执行的SQL语句”。因此,我们应该在"logback.xml"中配置这个Logger实例相应的<logger>标签,将level值设为合适的值,而将<root>标签的level值从"all"改为合适的"非all"值,因为如果Logger实例的Level过低,在项目运行中会有太多有效的日志记录请求,影响项目运行性能。
修改后"logback.xml"内容如下:
参考文献:
[1]http://code.google.com/p/log4jdbc/
假如我们采用"SLF4J+Logback"的日志框架解决方案,那么该如何配置Logback,使得能够记录“完整的执行的SQL语句”呢?
(假定通过"logback.xml"文件进行Logback配置)
首先有三点需要注意:
1)除非数据库管理模块自身(比如"mysql:mysql-connector-java")包含有记录“完整的执行的SQL语句”的日志操作语句,否则,我们再怎么配置Logback也无济于事。
2)数据库管理模块有可能不是使用SLF4J作为日志框架,此时需要"jcl-over-slf4j","log4j-over-slf4j","jul-to-slf4j"等日志框架桥接器。可以通过数据库管理模块的pom.xml中声明的日志框架依赖,来确定数据库管理模块所使用的日志框架。不过有个特殊情况,当数据库管理模块使用"Java Logging API"时,无需在pom.xml中声明依赖。因此,我们在搭建实验环境的时候总是添加"jul-to-slf4j"这个日志框架桥接器,并且修改"JDK_HOME/jre/lib/logging.properties"文件中的handlers参数值为"org.slf4j.bridge.SLF4JBridgeHandler"
3)在搭建实验环境,配置"logback.xml"文件的时候,为了排除“由于数据库管理模块的日志记录请求的Level值小于相应Logger实例的Level值,不能达到记录‘完整的执行的SQL语句’的目标”的干扰因素,配置<root>标签中的level值为"all"。
实验环境中的"logback.xml"文件内容如下:
<!--配置debug=true,从而打印任何内部状态下的信息--> <configuration debug="true"> <!--配置ConsoleAppender实例--> <appender name="console" class="ch.qos.logback.core.ConsoleAppender"> <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder"> <pattern>%-5level %logger %C %M %d{MM/dd-HH:mm:ss.SSS} [%thread] - %msg%n</pattern> </encoder> </appender> <!--可以通过<logger>标签,改变指定的Logger实例的Level值和绑定的Appender--> <!--在Logger实例层次结构中,该Logger实例处于最顶层,其下的子孙Logger实例会继承它的Level值和绑定的Appender,除非特别指定--> <root level="all"> <appender-ref ref="console"/> </root> </configuration>
接下来分别介绍4种场景下的Logback配置方案。
一、直接使用"mysql:mysql-connector-java"
在本场景中,查询SQL语句的时候,直接使用"mysql:mysql-connector-java"。查看"mysql:mysql-connector-java"的pom.xml文件,可以发现没有声明对任何日志框架的依赖,但还是有可能使用"Java Logging API"这个日志框架。
接下来搭建一个实验环境进行实验。
1、pom.xml
<dependencies> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.30</version> </dependency> <!--针对数据库管理模块使用Java Logging API日志框架的情况,配置"org.slf4j:jul-to-slf4j"桥接器--> <!--并且修改JDK_HOME/jre/lib/logging.properties文件中的handlers参数值为org.slf4j.bridge.SLF4JBridgeHandler--> <dependency> <groupId>org.slf4j</groupId> <artifactId>jul-to-slf4j</artifactId> <version>1.7.12</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>1.7.12</version> </dependency> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-classic</artifactId> <version>1.0.13</version> </dependency> </dependencies>
2、logback.xml
见“三点注意”中的logback.xml配置。
3、Java代码
import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; public class Simple { public static void main(String[] args) throws Exception { Class.forName("com.mysql.jdbc.Driver"); String mysqlUrl = "jdbc:mysql://127.0.0.1:3306/dslztx?useUnicode=true&characterEncoding=gbk&user=dsl&password=dsl"; String sql = "update activity set origin='china' where id=?"; Connection connection = DriverManager.getConnection(mysqlUrl); PreparedStatement statement = connection.prepareStatement(sql); statement.setInt(1, 1); statement.executeUpdate(); } }
4、运行结果
如图1,通过实验可以得出结论:在本场景中,无论如何配置"logback.xml",都不能达到记录“完整的执行的SQL语句”的目标。
图1
二、使用"com.googlecode.log4jdbc:log4jdbc"[1]
在本场景中,查询SQL语句的时候,使用"com.googlecode.log4jdbc:log4jdbc","com.googlecode.log4jdbc:log4jdbc"是一个中间层,底层还是使用"mysql:mysql-connector-java"。查看"com.googlecode.log4jdbc:log4jdbc"的pom.xml,可以发现依赖"org.slf4j:slf4j-api",即它使用SLF4J作为日志框架。
接下来搭建一个实验环境进行实验。
1、pom.xml
<dependencies> <dependency> <groupId>com.googlecode.log4jdbc</groupId> <artifactId>log4jdbc</artifactId> <version>1.2</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.30</version> </dependency> <!--针对数据库管理模块使用Java Logging API日志框架的情况,配置"org.slf4j:jul-to-slf4j"桥接器--> <!--并且修改JDK_HOME/jre/lib/logging.properties文件中的handlers参数值为org.slf4j.bridge.SLF4JBridgeHandler--> <dependency> <groupId>org.slf4j</groupId> <artifactId>jul-to-slf4j</artifactId> <version>1.7.12</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>1.7.12</version> </dependency> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-classic</artifactId> <version>1.0.13</version> </dependency> </dependencies>
2、logback.xml
见“三点注意”中的logback.xml配置。
3、Java代码
import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; public class Log4JDBC { public static void main(String[] args) throws Exception { Class.forName("net.sf.log4jdbc.DriverSpy"); String mysqlUrl = "jdbc:log4jdbc:mysql://127.0.0.1:3306/dslztx?useUnicode=true&characterEncoding=gbk&user=dsl&password=dsl"; String sql = "update activity set origin='china' where id=?"; Connection connection = DriverManager.getConnection(mysqlUrl); PreparedStatement statement = connection.prepareStatement(sql); statement.setInt(1, 1); statement.executeUpdate(); } }
4、运行结果
如图2,通过实验可以得出结论:在本场景下,能够达到记录“完整的执行的SQL语句”的目标。
图2
详细分析运行结果,可以发现名称为"jdbc.sqlonly"和"jdbc.sqltiming"的Logger实例能够记录“完整的执行的SQL语句”。因此,我们应该在"logback.xml"中配置这两个Logger实例相应的<logger>标签,将level值设为合适的值,而将<root>标签的level值从"all"改为合适的"非all"值,因为如果Logger实例的Level过低,在项目运行中会有太多有效的日志记录请求,影响项目运行性能。
修改后"logback.xml"内容如下:
<!--配置debug=true,从而打印任何内部状态下的信息--> <configuration debug="true"> <!--配置ConsoleAppender实例--> <appender name="console" class="ch.qos.logback.core.ConsoleAppender"> <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder"> <pattern>%-5level %logger %C %M %d{MM/dd-HH:mm:ss.SSS} [%thread] - %msg%n</pattern> </encoder> </appender> <!--可以通过<logger>标签,改变指定的Logger实例的Level值和绑定的Appender--> <logger name="jdbc.sqlonly" level="debug" additivitt="true"/> <logger name="jdbc.sqltiming" level="debug" additivitt="true"/> <!--在Logger实例层次结构中,该Logger实例处于最顶层,其下的子孙Logger实例会继承它的Level值和绑定的Appender,除非特别指定--> <root level="info"> <appender-ref ref="console"/> </root> </configuration>
三、使用"org.springframework:spring-jdbc"
在本场景中,查询SQL语句的时候,使用"org.springframework:spring-jdbc","org.springframework:spring-jdbc"是一个中间层,底层还是使用"mysql:mysql-connector-java"。查看"org.springframework:spring-jdbc"的pom.xml,可以发现它递归依赖"commons-logging:commons-logging",即它使用JCL作为日志框架,因而我们需要"jcl-over-slf4j"这个日志框架桥接器,并且需要在包含"org.springframework:spring-jdbc"依赖的时候,通过<exclusion>标签排除掉"commons-logging:commons-logging"依赖。
本场景中还需要有"com.mchange:c3p0"依赖,查看它的pom.xml,可以发现没有对日志框架的依赖,但是它很有可能选用"Java Logging API"作为日志框架。
接下来搭建一个实验环境进行实验。
1、pom.xml
<dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>3.2.3.RELEASE</version> <exclusions> <exclusion> <groupId>commons-logging</groupId> <artifactId>commons-logging</artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>com.mchange</groupId> <artifactId>c3p0</artifactId> <version>0.9.2</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.30</version> </dependency> <!--针对数据库管理模块使用Java Logging API日志框架的情况,配置"org.slf4j:jul-to-slf4j"桥接器--> <!--并且修改JDK_HOME/jre/lib/logging.properties文件中的handlers参数值为org.slf4j.bridge.SLF4JBridgeHandler--> <dependency> <groupId>org.slf4j</groupId> <artifactId>jul-to-slf4j</artifactId> <version>1.7.12</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>jcl-over-slf4j</artifactId> <version>1.7.12</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>1.7.12</version> </dependency> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-classic</artifactId> <version>1.0.13</version> </dependency> </dependencies>
2、logback.xml
见“三点注意”中的logback.xml配置。
3、Java代码
import com.mchange.v2.c3p0.ComboPooledDataSource; import org.springframework.jdbc.core.JdbcTemplate; public class SpringJdbcTemplate { public static void main(String[] args) throws Exception { ComboPooledDataSource dataSource = new ComboPooledDataSource(); dataSource.setDriverClass("com.mysql.jdbc.Driver"); dataSource.setJdbcUrl("jdbc:mysql://127.0.0.1:3306/dslztx?useUnicode=true&characterEncoding=gbk"); dataSource.setUser("dsl"); dataSource.setPassword("dsl"); JdbcTemplate template = new JdbcTemplate(dataSource); String sql = "update activity set origin='china' where id=?"; template.update(sql, 1); } }
4、运行结果
如图3,通过实验得出结论:能够达到记录“完整的执行的SQL语句”的目标。
图3
详细分析运行结果,可以发现名称为"org.springframework.jdbc.core.StatementCreatorUtils"的Logger实例能够记录“完整的执行的SQL语句”。因此,我们应该在“logback.xml”中配置这个Logger实例相应的<logger>标签,将level值设为合适的值,而将<root>标签的level值从"all"改为合适的"非all"值,因为如果Logger实例的Level过低,在项目运行中会有太多有效的日志记录请求,影响项目运行性能。
修改后“logback.xml”内容如下:
<!--配置debug=true,从而打印任何内部状态下的信息--> <configuration debug="true"> <!--配置ConsoleAppender实例--> <appender name="console" class="ch.qos.logback.core.ConsoleAppender"> <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder"> <pattern>%-5level %logger %C %M %d{MM/dd-HH:mm:ss.SSS} [%thread] - %msg%n</pattern> </encoder> </appender> <!--可以通过<logger>标签,改变指定的Logger实例的Level值和绑定的Appender--> <logger name="org.springframework.jdbc.core.StatementCreatorUtils" level="trace" additivity="true"/> <!--在Logger实例层次结构中,该Logger实例处于最顶层,其下的子孙Logger实例会继承它的Level值和绑定的Appender,除非特别指定--> <root level="info"> <appender-ref ref="console"/> </root> </configuration>
四、使用Mybatis
在本场景中,查询SQL语句的时候,使用“org.mybatis:mybatis","org.mybatis:mybatis"是一个中间层,底层还是使用"mysql:mysql-connector-java"。根据文章《Java日志框架——Mybatis选用的日志框架解决方案》,"org.mybatis:mybatis"动态确定选用的第三方日志框架,再结合"org.mybatis:mybatis"的pom.xml文件中的对日志框架依赖的"optional"属性值,可以知道,我们只要在项目中加入对SLF4J的依赖,就可以令mybatis使用SLF4J日志框架。
接下来搭建一个实验环境进行实验。
1、pom.xml
<dependencies> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.2.7</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.30</version> </dependency> <!--针对数据库管理模块使用Java Logging API日志框架的情况,配置"org.slf4j:jul-to-slf4j"桥接器--> <!--并且修改JDK_HOME/jre/lib/logging.properties文件中的handlers参数值为org.slf4j.bridge.SLF4JBridgeHandler--> <dependency> <groupId>org.slf4j</groupId> <artifactId>jul-to-slf4j</artifactId> <version>1.7.12</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>1.7.12</version> </dependency> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-classic</artifactId> <version>1.0.13</version> </dependency> </dependencies>
2、logback.xml
见“三点注意”中的logback.xml配置。
3、Java代码
import org.apache.ibatis.session.SqlSession; import org.apache.ibatis.session.SqlSessionFactory; import org.apache.ibatis.session.SqlSessionFactoryBuilder; import java.io.BufferedReader; import java.io.InputStreamReader; import java.util.HashMap; import java.util.Map; public class MybatisLog { public static void main(String[] args) throws Exception { BufferedReader reader = new BufferedReader(new InputStreamReader(MybatisLog.class.getResourceAsStream("/mybatis-config.xml"))); SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(reader, "mybatisDB"); reader.close(); SqlSession sqlSession = factory.openSession(); Map<String, Integer> map = new HashMap<String, Integer>(); map.put("id", 1); sqlSession.update("Activity.updateActivity", map); } }
4、运行结果
如图4,通过实验得到结论:能够达到记录“完整的执行的SQL语句”的目标。
图4
详细分析运行结果,可以发现名称为"Activity.updateActivity"的Logger实例能够记录“完整的执行的SQL语句”。因此,我们应该在"logback.xml"中配置这个Logger实例相应的<logger>标签,将level值设为合适的值,而将<root>标签的level值从"all"改为合适的"非all"值,因为如果Logger实例的Level过低,在项目运行中会有太多有效的日志记录请求,影响项目运行性能。
修改后"logback.xml"内容如下:
<!--配置debug=true,从而打印任何内部状态下的信息--> <configuration debug="true"> <!--配置ConsoleAppender实例--> <appender name="console" class="ch.qos.logback.core.ConsoleAppender"> <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder"> <pattern>%-5level %logger %C %M %d{MM/dd-HH:mm:ss.SSS} [%thread] - %msg%n</pattern> </encoder> </appender> <!--可以通过<logger>标签,改变指定的Logger实例的Level值和绑定的Appender--> <logger name="Activity.updateActivity" level="debug" additivity="true"/> <!--在Logger实例层次结构中,该Logger实例处于最顶层,其下的子孙Logger实例会继承它的Level值和绑定的Appender,除非特别指定--> <root level="info"> <appender-ref ref="console"/> </root> </configuration>
参考文献:
[1]http://code.google.com/p/log4jdbc/
相关文章推荐
- java反射
- java中常用数据类型转换器
- 从Struts2源码学习Struts2的工作原理
- hdu 1868 Consecutive sum Java 水题系列
- Java 迭代显示路径文件信息
- 解决eclipse不能
- Java Web项目结构
- java.io.StreamCorruptedException: invalid stream header: EFBFBDEF
- Java基础——反射
- JAVAWEB电影售票
- java基础--正则表达式
- Java集合的Set、List、Map异同分析
- JAVA实现的单例模式
- hdu 1870 愚人节的礼物 Java 水题系列
- [转]Eclipse 启动报错Failed to create the Java Virtual Machine的解决方法
- hdu 1860 统计字符 Java 水题系列
- spring常用的一些注解以及注解注入总结
- java中final,finally和finalize的区别
- Spring核心机制--依赖注入IOC
- Eclipse 安装插件 几乎就这么几个步骤,包括svn安装