log4jdbc简介

[TOC]

0 前言

使用java进行数据库操作时最痛苦的莫过于拼接SQL语句。在实际运行时往往需要查看<font color='red'>实际生成的SQL语句</font>和实际<font color='red'>传入的参数</font>,或许还会有查看SQL<font color='red'>执行时间</font>等的需求。
无论原生JDBC、dbutils、mybatis还是hibernate,使用log4j等日志框架可以看到生成的SQL,但是占位符和参数总是分开打印的。实在是不太友好。显示如下的效果:

select * from t_user where age>? and (sex=? or dept_id=?)

<font color='red'>log4jdbc</font>能很好的解决上述问题。使用log4jdbc之后的效果如下:

select * from t_user where age>1 and (sex=0 or dept_id='007')

1 log4jdbc简介

没有什么比官网对它的介绍更加贴切了:
log4jdbc is a Java JDBC driver that can log SQL and/or JDBC calls (and optionally SQL timing information) for other JDBC drivers using the Simple Logging Facade For Java (SLF4J) logging system.
但是,众所周知googlecode在国内的访问问题……
官网News一栏有如下消息:

2015-03-30: Due to Google Code shutting down soon, log4jdbc has moved to github at 2015-03-30: Due to Google Code shutting down soon, log4jdbc has moved to github at https://github.com/arthurblake/log4jdbc

2 特性

  1. 完全支持JDBC3和JDBC4
  2. 配置简单,一般情况下你只需要将你的DriverClass改为:net.sf.log4jdbc.DriverSpy,并在你的jdbcUrl之前拼接jdbc:log4
  3. 自动将占位符(?)替换为实际的参数
  4. 能够及时方便地显示SQL的实际执行时间
  5. 显示SQL Connection的数量的信息
  6. 能在JDK1.4+和SLF4J1.X上和大多数常见的JDBC驱动协同工作
  7. open source

3 使用

以下多数信息来自于官网

3.0 jar包的选择

JDK Version jar file
JDK 1.4 or 1.5 JDBC 3 version of log4jdbc
JDK 1.6 or 1.7 JDBC 4 version of log4jdbc

不了解 JDBC3 JDBC4

3.1 日志系统的选择

log4jdbc 使用Simple Logging Facade for Java (SLF4j) 作为日志系统,(SLF4J)是一个简单灵活的日志抽象层,可以方便的在以下日志系统之间切换:

  • Log4j
  • java.util logging in JDK 1.4
  • logback
  • Jakarta Commons Logging

下载 SLF4j,你将需要slf4j-api-1.5.0.jar和你实际所用的日志系统的jar包,或许还会有一个适配的中间插件jar包(取决于你使用的实际日志系统)。

3.2 更改DriverClass

log4jdbc "spy" driver 将会尝试着加载以下驱动:

Driver Class Database Type
oracle.jdbc.driver.OracleDriver Older Oracle Driver
oracle.jdbc.OracleDriver Newer Oracle Driver
com.sybase.jdbc2.jdbc.SybDriver Sybase
net.sourceforge.jtds.jdbc.Driver jTDS SQL Server & Sybase driver
com.microsoft.jdbc.sqlserver.SQLServerDriver Microsoft SQL Server 2000 driver
com.microsoft.sqlserver.jdbc.SQLServerDriver Microsoft SQL Server 2005 driver
weblogic.jdbc.sqlserver.SQLServerDriver Weblogic SQL Server driver
com.informix.jdbc.IfxDriver Informix
org.apache.derby.jdbc.ClientDriver Apache Derby client/server driver, aka the Java DB
org.apache.derby.jdbc.EmbeddedDriver Apache Derby embedded driver, aka the Java DB
com.mysql.jdbc.Driver MySQL
org.postgresql.Driver PostgresSQL
org.hsqldb.jdbcDriver HSQLDB pure Java database
org.h2.Driver H2 pure Java database

<font color="blue">注意:</font> 如果你要使用一个不在上表中的Driver,请提供log4jdbc.drivers配置,多个之间用逗号分隔,不带空格。

3.3 prepend jdbcUrl属性

例如:
你的url为: url= <font color="blue">jdbc:mysql://localhost:3306/mvn</font>
应该改为: url= <font color="blue"><font color="red">jdbc:log4</font>jdbc:mysql://localhost:3306/mvn</font>

3.4 建立你的日志系统

log4jdbc使用5种logger:

logger 描述 since
jdbc.sqlonly 仅仅记录 SQL 语句,会将占位符替换为实际的参数 1.0
jdbc.sqltiming 包含 SQL 语句实际的执行时间 1.0
jdbc.audit 除了 ResultSet 之外的所有JDBC调用信息,篇幅较长 1.0
jdbc.resultset 包含 ResultSet 的信息,输出篇幅较长 1.0
jdbc.connection 输出了 Connection 的 open、close 等信息 1.2alpha1

此外还有个叫 log4jdbc.debug 的 logger,用于log4jdbc的内部调试,会输出 log4jdbc spy 加载驱动的时的信息,如driver found 或 not found 等信息。

3.5 修改debug选项--可选

可以在类路径下提供一个名为 <font color="blue">log4jdbc.properties </font>的配置文件,用以修改一些默认的debug属性。
其常用属性如下(来自于 官网 文档):

property default description since
log4jdbc.drivers log4jdbc 加载的一个或多个驱动的全类名。如果有多个,每个之间用逗号分隔(不带空格).对应常见的 JDBC drivers 此选项不是必须的。但是如果需要多个 driver ,需要配置该选项。 1.0
log4jdbc.auto.load.popular.drivers true 自动加载常用的jdbc driver,如果设置为false,则必须提供 log4jdbc.drivers 属性。 1.2beta2
log4jdbc.debug.stack.prefix The partial (or full) package prefix for the package name of your application. The call stack will be searched down to the first occurrence of a class that has the matching prefix. If this is not set, the actual class that called into log4jdbc is used in the debug output (in many cases this will be a connection pool class.) For example, setting a system property such as this: -Dlog4jdbc.debug.stack.prefix=com.mycompany.myapp Would cause the call stack to be searched for the first call that came from code in the com.mycompany.myapp package or below, thus if all of your sql generating code was in code located in the com.mycompany.myapp package or any subpackages, this would be printed in the debug information, rather than the package name for a connection pool, object relational system, etc. 1.0
log4jdbc.sqltiming.warn.threshold 毫秒值.执行时间超过该值的SQL语句将被记录为warn级别. 1.1beta1
log4jdbc.sqltiming.error.threshold 毫秒值.执行时间超过该值的SQL语句将被记录为error级别. 1.1beta1
log4jdbc.dump.booleanastruefalse false 当该值为 false 时,boolean 值显示为 0 和 1 ,为 true 时 boolean 值显示为 true 和 false 1.2alpha1
log4jdbc.dump.sql.maxlinelength 90 SQL 分行的最大值 1.2alpha1
log4jdbc.dump.fulldebugstacktrace false 设置为 true 将会输出大篇幅的 debug信息 1.2alpha1
log4jdbc.dump.sql.select true 是否输出 select 语句 1.2alpha1
log4jdbc.dump.sql.insert true 是否输出 insert 语句 1.2alpha1
log4jdbc.dump.sql.delete true 是否输出 delete 语句 1.2alpha1
log4jdbc.dump.sql.update true 是否输出 update 语句 1.2alpha1
log4jdbc.dump.sql.create true 是否输出 create 语句 1.2alpha1
log4jdbc.dump.sql.addsemicolon false 是否在 SQL 的行末添加一个分号 1.2alpha1
log4jdbc.statement.warn false Set this to true to display warnings (Why would you care?) in the log when Statements are used in the log. NOTE, this was always true in releases previous to 1.2alpha2. It is false by default starting with release 1.2 alpha 2. 1.2alpha2
log4jdbc.trim.sql true Set this to false to not trim the logged SQL. (Previous versions always trimmed the SQL.) 1.2beta2
log4jdbc.trim.sql.extrablanklines true Set this to false to not trim extra blank lines in the logged SQL (by default, when more than one blank line in a row occurs, the contiguous lines are collapsed to just one blank line.) (Previous versions didn't trim extra blank lines at all.) 1.2
log4jdbc.suppress.generated.keys.exception false Set to true to ignore any exception produced by the method, Statement.getGeneratedKeys() (Useful for using log4jdbc with Coldfusion.) 1.2beta2

4 实战

4.0 纯JDBC--log4j

4.0.0 jar包

maven 依赖

<dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.4</version>
            <scope>test</scope>
        </dependency>
        <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.35</version>
        </dependency>
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.16</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-log4j12</artifactId>
            <version>1.6.0</version>
        </dependency>
    </dependencies>

4.0.1 配置文件

  1. log4j.properties
    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
    
    log4j.logger.jdbc.sqlonly=console
    log4j.appender.console=org.apache.log4j.ConsoleAppender
    log4j.appender.console.layout=org.apache.log4j.PatternLayout
    log4j.appender.console.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss.SSS} %m%n%n
    #log4j.logger.jdbc.sqltiming=INFO,console 
    #log4j.logger.jdbc.connection=INFO,console
    
    log4j.rootLogger=DEBUG, console
    
  2. dbconfig.properties
    url:jdbc:log4jdbc:mysql://localhost:3306/mvn
    driverClassName:net.sf.log4jdbc.DriverSpy
    username:root
    password:root
    
  3. log4jdbc.properties
    log4jdbc.debug.stack.prefix=software_test.log4jdbc
    log4jdbc.drivers=com.mysql.jdbc.Driver
    log4jdbc.auto.load.popular.drivers=true
    
    log4jdbc.statement.warn=true
    log4jdbc.sqltiming.warn.threshold=1000
    log4jdbc.sqltiming.error.threshold=3000
    log4jdbc.dump.booleanastruefalse=true
    log4jdbc.dump.sql.maxlinelength=90
    log4jdbc.dump.fulldebugstacktrace=false
    
    log4jdbc.dump.sql.select=true
    log4jdbc.dump.sql.insert=true
    log4jdbc.dump.sql.delete=true
    log4jdbc.dump.sql.update=true
    log4jdbc.dump.sql.create=true
    log4jdbc.dump.sql.addsemicolon=false
    
    log4jdbc.trim.sql=true
    log4jdbc.trim.sql.extrablanklines=true
    log4jdbc.suppress.generated.keys.exception=false
    

4.0.2 测试

```java
import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.Properties;

import org.junit.Test;

public class SimpleTest {

    @Test
    public void test1() {
        String sql = "select * " + "from t_user where id=?";
        Connection conn = null;
        PreparedStatement ps = null;
        try {
            conn = getConnection();
            ps = conn.prepareStatement(sql);
            ps.setInt(1, 2);
            ps.executeQuery();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

    public Connection getConnection() throws IOException, SQLException,
            ClassNotFoundException {
        String driverClassName = null;
        String jdbcUrl = null;
        String user = null;
        String password = null;
        // 读取类路径下的配置文件
        InputStream in = getClass().getClassLoader().getResourceAsStream(
                "dbconfig.properties");
        Properties properties = new Properties();
        properties.load(in);
        driverClassName = properties.getProperty("driverClassName");
        jdbcUrl = properties.getProperty("url");
        user = properties.getProperty("username");
        password = properties.getProperty("password");
        Class.forName(driverClassName);
        // 连接信息
        Properties info = new Properties();
        info.put("user", user);
        info.put("password", password);
        // 获取连接
        Connection connection = DriverManager.getConnection(jdbcUrl, user,
                password);
        return connection;
    }
}
```

4.1 DataSource--c3p0

截至目前为止,官网 对于log4jdbc和数据源的使用还没有一个很好地例子,以下是官网的截图:

log4jdbc对于数据源的说明

本人尝试了一下C3P0数据源,不到之处请指正。

4.1.0 jar包

maven 依赖

    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.4</version>
            <scope>test</scope>
        </dependency>
        <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.35</version>
        </dependency>
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.16</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-log4j12</artifactId>
            <version>1.6.0</version>
        </dependency>
        <dependency>
            <groupId>c3p0</groupId>
            <artifactId>c3p0</artifactId>
            <version>0.9.1.2</version>
        </dependency>
    </dependencies>

4.1.1 配置文件

此处只需要 log4j.properties 和log4jdbc.properties 两个配置文件即可,配置同4.0中的配置文件。

4.1.2 测试

package software_test.log4jdbc;

import java.sql.Connection;
import java.sql.PreparedStatement;

import org.junit.Test;

import com.mchange.v2.c3p0.ComboPooledDataSource;

public class DataSourceTest {

    @Test
    public void testC3P0() {
        try {
            ComboPooledDataSource dataSource = new ComboPooledDataSource();
            dataSource.setUser("root");
            dataSource.setPassword("1234");
            dataSource.setDriverClass("net.sf.log4jdbc.DriverSpy");
            dataSource.setJdbcUrl("jdbc:log4jdbc:mysql://localhost:3306/mvn");
            dataSource.setMaxPoolSize(50);
            Connection conn = dataSource.getConnection();
            String sql = "select * " + "from t_user where id=?";
            PreparedStatement ps = null;
            ps = conn.prepareStatement(sql);
            ps.setInt(1, 2);
            ps.executeQuery();
            ps.close();
            conn.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

5 声明

在此将log4jdbc的使用结合官网的帮助文档中主要的一部分罗列出来。部分不太常用或理解不到位的没有翻译,怕误人子弟,有翻译不周的地方或理解不到位的地方欢迎指正。
实战部分,以后会抽时间加入其它的使用方式。
<font color="red">转载请保留出处。</font>

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 151,829评论 1 331
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 64,603评论 1 273
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 101,846评论 0 226
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 42,600评论 0 191
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 50,780评论 3 272
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 39,695评论 1 192
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,136评论 2 293
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 29,862评论 0 182
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 33,453评论 0 229
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 29,942评论 2 233
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,347评论 1 242
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 27,790评论 2 236
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,293评论 3 221
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 25,839评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,448评论 0 181
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 34,564评论 2 249
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 34,623评论 2 249

推荐阅读更多精彩内容