log4jdbc簡(jiǎn)介

[TOC]

0 前言

使用java進(jìn)行數(shù)據(jù)庫(kù)操作時(shí)最痛苦的莫過(guò)于拼接SQL語(yǔ)句蚯舱。在實(shí)際運(yùn)行時(shí)往往需要查看<font color='red'>實(shí)際生成的SQL語(yǔ)句</font>和實(shí)際<font color='red'>傳入的參數(shù)</font>,或許還會(huì)有查看SQL<font color='red'>執(zhí)行時(shí)間</font>等的需求昧诱。
無(wú)論原生JDBC晓淀、dbutils、mybatis還是hibernate盏档,使用log4j等日志框架可以看到生成的SQL,但是占位符和參數(shù)總是分開打印的燥爷。實(shí)在是不太友好蜈亩。顯示如下的效果:

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

<font color='red'>log4jdbc</font>能很好的解決上述問(wèn)題。使用log4jdbc之后的效果如下:

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

1 log4jdbc簡(jiǎn)介

沒(méi)有什么比官網(wǎng)對(duì)它的介紹更加貼切了:
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在國(guó)內(nèi)的訪問(wèn)問(wèn)題……
官網(wǎng)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. 配置簡(jiǎn)單稚配,一般情況下你只需要將你的DriverClass改為:net.sf.log4jdbc.DriverSpy,并在你的jdbcUrl之前拼接jdbc:log4
  3. 自動(dòng)將占位符(?)替換為實(shí)際的參數(shù)
  4. 能夠及時(shí)方便地顯示SQL的實(shí)際執(zhí)行時(shí)間
  5. 顯示SQL Connection的數(shù)量的信息
  6. 能在JDK1.4+和SLF4J1.X上和大多數(shù)常見(jiàn)的JDBC驅(qū)動(dòng)協(xié)同工作
  7. open source

3 使用

以下多數(shù)信息來(lái)自于官網(wǎng)

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)是一個(gè)簡(jiǎn)單靈活的日志抽象層,可以方便的在以下日志系統(tǒng)之間切換:

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

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

3.2 更改DriverClass

log4jdbc "spy" driver 將會(huì)嘗試著加載以下驅(qū)動(dòng):

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> 如果你要使用一個(gè)不在上表中的Driver,請(qǐng)?zhí)峁﹍og4jdbc.drivers配置尊流,多個(gè)之間用逗號(hào)分隔帅戒,不帶空格。

3.3 prepend jdbcUrl屬性

例如:
你的url為: url= <font color="blue">jdbc:mysql://localhost:3306/mvn</font>
應(yīng)該改為: 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 語(yǔ)句崖技,會(huì)將占位符替換為實(shí)際的參數(shù) 1.0
jdbc.sqltiming 包含 SQL 語(yǔ)句實(shí)際的執(zhí)行時(shí)間 1.0
jdbc.audit 除了 ResultSet 之外的所有JDBC調(diào)用信息逻住,篇幅較長(zhǎng) 1.0
jdbc.resultset 包含 ResultSet 的信息,輸出篇幅較長(zhǎng) 1.0
jdbc.connection 輸出了 Connection 的 open迎献、close 等信息 1.2alpha1

此外還有個(gè)叫 log4jdbc.debug 的 logger瞎访,用于log4jdbc的內(nèi)部調(diào)試,會(huì)輸出 log4jdbc spy 加載驅(qū)動(dòng)的時(shí)的信息吁恍,如driver found 或 not found 等信息装诡。

3.5 修改debug選項(xiàng)--可選

可以在類路徑下提供一個(gè)名為 <font color="blue">log4jdbc.properties </font>的配置文件,用以修改一些默認(rèn)的debug屬性践盼。
其常用屬性如下(來(lái)自于 官網(wǎng) 文檔):

property default description since
log4jdbc.drivers log4jdbc 加載的一個(gè)或多個(gè)驅(qū)動(dòng)的全類名鸦采。如果有多個(gè),每個(gè)之間用逗號(hào)分隔(不帶空格).對(duì)應(yīng)常見(jiàn)的 JDBC drivers 此選項(xiàng)不是必須的咕幻。但是如果需要多個(gè) driver 渔伯,需要配置該選項(xiàng)。 1.0
log4jdbc.auto.load.popular.drivers true 自動(dòng)加載常用的jdbc driver肄程,如果設(shè)置為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í)行時(shí)間超過(guò)該值的SQL語(yǔ)句將被記錄為warn級(jí)別. 1.1beta1
log4jdbc.sqltiming.error.threshold 毫秒值.執(zhí)行時(shí)間超過(guò)該值的SQL語(yǔ)句將被記錄為error級(jí)別. 1.1beta1
log4jdbc.dump.booleanastruefalse false 當(dāng)該值為 false 時(shí)蓝厌,boolean 值顯示為 0 和 1 玄叠,為 true 時(shí) boolean 值顯示為 true 和 false 1.2alpha1
log4jdbc.dump.sql.maxlinelength 90 SQL 分行的最大值 1.2alpha1
log4jdbc.dump.fulldebugstacktrace false 設(shè)置為 true 將會(huì)輸出大篇幅的 debug信息 1.2alpha1
log4jdbc.dump.sql.select true 是否輸出 select 語(yǔ)句 1.2alpha1
log4jdbc.dump.sql.insert true 是否輸出 insert 語(yǔ)句 1.2alpha1
log4jdbc.dump.sql.delete true 是否輸出 delete 語(yǔ)句 1.2alpha1
log4jdbc.dump.sql.update true 是否輸出 update 語(yǔ)句 1.2alpha1
log4jdbc.dump.sql.create true 是否輸出 create 語(yǔ)句 1.2alpha1
log4jdbc.dump.sql.addsemicolon false 是否在 SQL 的行末添加一個(gè)分號(hào) 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 實(shí)戰(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 測(cè)試

```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

截至目前為止,官網(wǎng) 對(duì)于log4jdbc和數(shù)據(jù)源的使用還沒(méi)有一個(gè)很好地例子,以下是官網(wǎng)的截圖:

log4jdbc對(duì)于數(shù)據(jù)源的說(shuō)明

本人嘗試了一下C3P0數(shù)據(jù)源拓提,不到之處請(qǐng)指正读恃。

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 兩個(gè)配置文件即可,配置同4.0中的配置文件代态。

4.1.2 測(cè)試

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的使用結(jié)合官網(wǎng)的幫助文檔中主要的一部分羅列出來(lái)寺惫。部分不太常用或理解不到位的沒(méi)有翻譯,怕誤人子弟蹦疑,有翻譯不周的地方或理解不到位的地方歡迎指正西雀。
實(shí)戰(zhàn)部分,以后會(huì)抽時(shí)間加入其它的使用方式歉摧。
<font color="red">轉(zhuǎn)載請(qǐng)保留出處艇肴。</font>

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末腔呜,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子再悼,更是在濱河造成了極大的恐慌核畴,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,386評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件帮哈,死亡現(xiàn)場(chǎng)離奇詭異膛檀,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)娘侍,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,142評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門咖刃,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人憾筏,你說(shuō)我怎么就攤上這事嚎杨。” “怎么了氧腰?”我有些...
    開封第一講書人閱讀 164,704評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵枫浙,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我古拴,道長(zhǎng)箩帚,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,702評(píng)論 1 294
  • 正文 為了忘掉前任黄痪,我火速辦了婚禮紧帕,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘桅打。我一直安慰自己是嗜,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,716評(píng)論 6 392
  • 文/花漫 我一把揭開白布挺尾。 她就那樣靜靜地躺著鹅搪,像睡著了一般。 火紅的嫁衣襯著肌膚如雪遭铺。 梳的紋絲不亂的頭發(fā)上丽柿,一...
    開封第一講書人閱讀 51,573評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音掂僵,去河邊找鬼航厚。 笑死,一個(gè)胖子當(dāng)著我的面吹牛锰蓬,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播眯漩,決...
    沈念sama閱讀 40,314評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼芹扭,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼麻顶!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起舱卡,我...
    開封第一講書人閱讀 39,230評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤辅肾,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后轮锥,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體矫钓,經(jīng)...
    沈念sama閱讀 45,680評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,873評(píng)論 3 336
  • 正文 我和宋清朗相戀三年舍杜,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了新娜。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,991評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡既绩,死狀恐怖概龄,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情饲握,我是刑警寧澤私杜,帶...
    沈念sama閱讀 35,706評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站救欧,受9級(jí)特大地震影響衰粹,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜笆怠,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,329評(píng)論 3 330
  • 文/蒙蒙 一铝耻、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧骑疆,春花似錦田篇、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,910評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至诈火,卻和暖如春兽赁,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背冷守。 一陣腳步聲響...
    開封第一講書人閱讀 33,038評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工刀崖, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人拍摇。 一個(gè)月前我還...
    沈念sama閱讀 48,158評(píng)論 3 370
  • 正文 我出身青樓亮钦,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親充活。 傳聞我的和親對(duì)象是個(gè)殘疾皇子蜂莉,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,941評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容