log4jdbc簡介

[TOC]

0 前言

使用java進行數據庫操作時最痛苦的莫過于拼接SQL語句。在實際運行時往往需要查看<font color='red'>實際生成的SQL語句</font>和實際<font color='red'>傳入的參數</font>,或許還會有查看SQL<font color='red'>執(zhí)行時間</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的實際執(zhí)行時間
  5. 顯示SQL Connection的數量的信息
  6. 能在JDK1.4+和SLF4J1.X上和大多數常見的JDBC驅動協(xié)同工作
  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 日志系統(tǒng)的選擇

log4jdbc 使用Simple Logging Facade for Java (SLF4j) 作為日志系統(tǒng),(SLF4J)是一個簡單靈活的日志抽象層,可以方便的在以下日志系統(tǒng)之間切換:

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

下載 SLF4j,你將需要slf4j-api-1.5.0.jar和你實際所用的日志系統(tǒng)的jar包,或許還會有一個適配的中間插件jar包(取決于你使用的實際日志系統(tǒng))。

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,請?zhí)峁﹍og4jdbc.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 建立你的日志系統(tǒng)

log4jdbc使用5種logger:

logger 描述 since
jdbc.sqlonly 僅僅記錄 SQL 語句,會將占位符替換為實際的參數 1.0
jdbc.sqltiming 包含 SQL 語句實際的執(zhí)行時間 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 毫秒值.執(zhí)行時間超過該值的SQL語句將被記錄為warn級別. 1.1beta1
log4jdbc.sqltiming.error.threshold 毫秒值.執(zhí)行時間超過該值的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 實戰(zhàn)

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的使用結合官網的幫助文檔中主要的一部分羅列出來。部分不太常用或理解不到位的沒有翻譯,怕誤人子弟,有翻譯不周的地方或理解不到位的地方歡迎指正。
實戰(zhàn)部分,以后會抽時間加入其它的使用方式。
<font color="red">轉載請保留出處。</font>

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,182評論 6 543
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 99,489評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,290評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,776評論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,510評論 6 412
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,866評論 1 328
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,860評論 3 447
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 43,036評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發(fā)現(xiàn)了一具尸體,經...
    沈念sama閱讀 49,585評論 1 336
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,331評論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,536評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,058評論 5 363
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 44,754評論 3 349
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,154評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,469評論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,273評論 3 399
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,505評論 2 379

推薦閱讀更多精彩內容