Java日志框架——查看“完整的执行的SQL语句”

项目开发中,在调试的时候,经常会有查看“完整的执行的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语句’的目标”的干扰因素,配置标签中的level值为"all"。
实验环境中的"logback.xml"文件内容如下:



    
    
        
            %-5level %logger %C %M %d{MM/dd-HH:mm:ss.SSS} [%thread] - %msg%n
        
    

    

     
    
        
    


接下来分别介绍4种场景下的Logback配置方案。

一、直接使用"mysql:mysql-connector-java"
在本场景中,查询SQL语句的时候,直接使用"mysql:mysql-connector-java"。查看"mysql:mysql-connector-java"的pom.xml文件,可以发现没有声明对任何日志框架的依赖,但还是有可能使用"Java Logging API"这个日志框架。
接下来搭建一个实验环境进行实验。
1、pom.xml

        
            mysql
            mysql-connector-java
            5.1.30
        
 
        
        
            org.slf4j
            jul-to-slf4j
            1.7.12
        
        
            org.slf4j
            slf4j-api
            1.7.12
        
        
            ch.qos.logback
            logback-classic
            1.0.13
        


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

        
            com.googlecode.log4jdbc
            log4jdbc
            1.2
        
        
            mysql
            mysql-connector-java
            5.1.30
        
        
        
        
            org.slf4j
            jul-to-slf4j
            1.7.12
        
        
            org.slf4j
            slf4j-api
            1.7.12
        
        
            ch.qos.logback
            logback-classic
            1.0.13
        


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实例相应的标签,将level值设为合适的值,而将标签的level值从"all"改为合适的"非all"值,因为如果Logger实例的Level过低,在项目运行中会有太多有效的日志记录请求,影响项目运行性能。
修改后"logback.xml"内容如下:



    
    
        
            %-5level %logger %C %M %d{MM/dd-HH:mm:ss.SSS} [%thread] - %msg%n
        
    

    
    

    

    
    
        
    

三、使用"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"依赖的时候,通过标签排除掉"commons-logging:commons-logging"依赖。
本场景中还需要有"com.mchange:c3p0"依赖,查看它的pom.xml,可以发现没有对日志框架的依赖,但是它很有可能选用"Java Logging API"作为日志框架。
接下来搭建一个实验环境进行实验。
1、pom.xml

        
            org.springframework
            spring-jdbc
            3.2.3.RELEASE
            
                
                    commons-logging
                    commons-logging
                
            
        
        
            com.mchange
            c3p0
            0.9.2
        
        
            mysql
            mysql-connector-java
            5.1.30
        
        
        
        
            org.slf4j
            jul-to-slf4j
            1.7.12
        
        
            org.slf4j
            jcl-over-slf4j
            1.7.12
        
        
            org.slf4j
            slf4j-api
            1.7.12
        
        
            ch.qos.logback
            logback-classic
            1.0.13
        


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实例相应的标签,将level值设为合适的值,而将标签的level值从"all"改为合适的"非all"值,因为如果Logger实例的Level过低,在项目运行中会有太多有效的日志记录请求,影响项目运行性能。
修改后“logback.xml”内容如下:



    
    
        
            %-5level %logger %C %M %d{MM/dd-HH:mm:ss.SSS} [%thread] - %msg%n
        
    

    
    

    
    
        
    


四、使用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
 
        
            org.mybatis
            mybatis
            3.2.7
        
        
            mysql
            mysql-connector-java
            5.1.30
        
        
        
        
            org.slf4j
            jul-to-slf4j
            1.7.12
        
        
            org.slf4j
            slf4j-api
            1.7.12
        
        
            ch.qos.logback
            logback-classic
            1.0.13
        


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 map = new HashMap();
        map.put("id", 1);
        sqlSession.update("Activity.updateActivity", map);
    }
}

4、运行结果

如图4,通过实验得到结论:能够达到记录“完整的执行的SQL语句”的目标。

                                                                                                                                  图4


详细分析运行结果,可以发现名称为"Activity.updateActivity"的Logger实例能够记录“完整的执行的SQL语句”。因此,我们应该在"logback.xml"中配置这个Logger实例相应的标签,将level值设为合适的值,而将标签的level值从"all"改为合适的"非all"值,因为如果Logger实例的Level过低,在项目运行中会有太多有效的日志记录请求,影响项目运行性能。
修改后"logback.xml"内容如下:



    
    
        
            %-5level %logger %C %M %d{MM/dd-HH:mm:ss.SSS} [%thread] - %msg%n
        
    

    
    
 
    
    
        
    



参考文献:

[1]http://code.google.com/p/log4jdbc/

你可能感兴趣的:(数据区)