mybatis开启log_mybatis打印sql日志

mybatis支持使用多种日志框架来打印sql,包括:slf4j、commons-logging、log4j、log4j2、jdk logging、stdout、no logging等。因此在打印日志时,我们首要确定自己使用的日志框架是什么,然后进行相应的配置。

对于从本教程刚刚开始学习mybatis的读者,可以在项目中引入log4j的依赖,然后在classpath下新增配置文件log4j.properties,即可打印出sql,内容如下:# 设置root logger日志打印级别为INFO,日志输出到STDOUT这个appender中

log4j.rootLogger=DEBUG,STDOUT

# 定义stdout这个STDOUT,其实现类为ConsoleAppender.表示日志输出到控制台中,读者可以使用其他appender,如DailyRollingFileAppender

log4j.appender.STDOUT=org.apache.log4j.ConsoleAppender

log4j.appender.STDOUT.layout=org.apache.log4j.PatternLayout

log4j.appender.STDOUT.layout.ConversionPattern=%d [%t] %-5p %c %x - %m%n

下面的内容,主要针对已经有一定mybatis使用经验,但是被打印sql的问题所困扰的用户。笔者在2.1、2.2、2.3小节中分别列出了log4j、log4j2、loback的配置方式 。但是还是希望读者按照顺序阅读,笔者将会通过深入的讲解,让你彻底掌握这个问题。

在使用mybatis打印sql日志时需要注意的几点,笔者至于让读者彻底掌握不同版本的mybatis如何打印日志。打印sql日志的logger一定要是debug级别的(注意这里说的不是root logger'),在其他级别下不论如何配置,mybatis也不会打印sql日志

mybatis 3.0.6,3.1.0,3.2.0版本前后打印日志的配置方式是不同的,这也是我们经常在网上照搬一些配置,但是依然打印不了sql的原因(博客的搬运工实在太多)。

当应用中存在多种日志框架jar包的依赖时,如果没有进行合适的配置,也是无法打印sql的。例如slf4j和commons-logging都是facade设计模式的实现,用于统一各种日志框架,底层依赖于具体的日志框架实现如log4j、logback、log4j2、jdk logging,并且需要引入相应的桥接jar依赖。

mybatis 版本>=3.2.0之后,元素中提供了logPrefix和logImpl配置项来帮助配置日志框架,这也是笔者建议的mybatis日志打印方式

1 不同版本的mybatis的日志实现

mybatis打印日志是通过org.apache.ibatis.logging.jdbc包下面的ConnectionLogger、StatementLogger、PreparedStatementLogger和ResultSetLogger进行的。在mybatis 3.0.6,3.1.0,3.2.0之后,这几个类的实现方式各不相同,导致打印sql日志的配置方式也发生了变化。

下面分别介绍不同的mybatis版本中,实现的区别。

1.1 不同版本logger实现的区别

以PreparedStatementLogger为例,不同版本的实现如下所示:

mybatis版本<=3.0.6

3.0.6

这两个版本之间只发布了3.1.0和3.1.1两个版本,以3.1.1版本为例,PreparedStatementLogger实现如下:

mybatis>=3.2.0

1.2 不同版本的日志打印效果演示

不同版本实现的区别在于logger的名称不同,以log4j为例:

1.2.1 mybatis版本<=3.0.6

logger的名字都以java.sql为前缀。我们可以按照如下方式配置log4j.properties# 设置root logger日志打印级别为INFO,日志输出到STDOUT这个appender中

log4j.rootLogger=INFO,STDOUT

# 定义stdout这个STDOUT,其实现类为ConsoleAppender.表示日志输出到控制台中,读者可以使用其他appender,如DailyRollingFileAppender

log4j.appender.STDOUT=org.apache.log4j.ConsoleAppender

log4j.appender.STDOUT.layout=org.apache.log4j.PatternLayout

log4j.appender.STDOUT.layout.ConversionPattern=%d [%t] %-5p %c %x - %m%n

#设置mybatis打印sql日志

log4j.logger.java.sql=DEBUG

#等价于以下四行配置

#log4j.logger.java.sql.Connection=DEBUG

#log4j.logger.java.sql.Statement=DEBUG

#log4j.logger.java.sql.PreparedStatement=DEBUG

#log4j.logger.java.sql.ResultSet=DEBUG

此时打印的日志效果如下所示:2017-11-27 22:18:58,128 [main] DEBUG java.sql.Connection  - ooo Connection Opened

2017-11-27 22:18:58,240 [main] DEBUG java.sql.PreparedStatement  - ==>  Executing: select id,name,age from user where id= ?

2017-11-27 22:18:58,241 [main] DEBUG java.sql.PreparedStatement  - ==> Parameters: 1(Integer)

2017-11-27 22:18:58,270 [main] DEBUG java.sql.ResultSet  - <==    Columns: id, name, age

2017-11-27 22:18:58,270 [main] DEBUG java.sql.ResultSet  - <==        Row: 1, tianshouzhi, 26

2017-11-27 22:18:58,272 [main] DEBUG java.sql.Connection  - xxx Connection Closed

1.2.2 mybatis>=3.2.0

默认logger的名字为namespace.id。其中namespace指的是mapper映射文件的namespace属性,id指的是配置的sql的id属性。如下图所示:

此时我们可以按照如下方式配置log4j.properties# 设置root logger日志打印级别为INFO,日志输出到STDOUT这个appender中

log4j.rootLogger=INFO,STDOUT

# 定义stdout这个STDOUT,其实现类为ConsoleAppender.表示日志输出到控制台中,读者可以使用其他appender,如DailyRollingFileAppender

log4j.appender.STDOUT=org.apache.log4j.ConsoleAppender

log4j.appender.STDOUT.layout=org.apache.log4j.PatternLayout

log4j.appender.STDOUT.layout.ConversionPattern=%d [%t] %-5p %c %x - %m%n

#设置mybatis打印sql日志,其中com.tianshouzhi.mybatis是所有mapper映射文件namespace属性的公共前缀

log4j.logger.com.tianshouzhi.mybatis=DEBUG

这里配置了一个logger,名字为com.tianshouzhi.mybatis,其是所有mapper映射文件namespace属性的公共前缀。

此时打印效果如下:2017-11-27 22:58:30,816 [main] DEBUG com.tianshouzhi.mybatis.quickstart.mapper.UserMapper.testResultMap  - ooo Using Connection [com.mysql.jdbc.JDBC4Connection@5c533a2]

2017-11-27 22:58:30,819 [main] DEBUG com.tianshouzhi.mybatis.quickstart.mapper.UserMapper.testResultMap  - ==>  Preparing: select id,name,age from user where id= ?

2017-11-27 22:58:30,911 [main] DEBUG com.tianshouzhi.mybatis.quickstart.mapper.UserMapper.testResultMap  - ==> Parameters: 1(Integer)

这种方式的好处是,一个sql执行过程中,经历的ConnectionLogger、StatementLogger、PreparedStatementLogger和ResultSetLogger内部在打印日志时,内部实际上引用的都是同一个底层logger实例。而通过namespace.sqlId作为logger的名称,在查看日志时,很容易串联起来一个sql从获取连接-->执行-->结果封装的整个过程。

特别的,mybatis 3.2.0版本中,我们可以在mybatis-config.xml文件中的在settings元素中可以配置logPrefix和logImpl配置项。例如,如果我们的项目中,mapper映射文件的namespace属性值各不相同,此时我们可以为所有的logger的名字加上一个公共的前缀,如:

此时修改log4.properties配置如下:# 设置root logger日志打印级别为INFO,日志输出到STDOUT这个appender中

log4j.rootLogger=INFO,STDOUT

# 定义stdout这个STDOUT,其实现类为ConsoleAppender.表示日志输出到控制台中,读者可以使用其他appender,如DailyRollingFileAppender

log4j.appender.STDOUT=org.apache.log4j.ConsoleAppender

log4j.appender.STDOUT.layout=org.apache.log4j.PatternLayout

log4j.appender.STDOUT.layout.ConversionPattern=%d [%t] %-5p %c %x - %m%n

#设置mybatis打印sql日志,注意这里的mybatis与logPrefix相匹配

log4j.logger.mybatis=DEBUG

此时sql的打印效果如下:2017-11-27 22:59:21,622 [main] DEBUG mybatis.com.tianshouzhi.mybatis.quickstart.mapper.UserMapper.testResultMap  - ooo Using Connection [com.mysql.jdbc.JDBC4Connection@66869e50]

2017-11-27 22:59:21,625 [main] DEBUG mybatis.com.tianshouzhi.mybatis.quickstart.mapper.UserMapper.testResultMap  - ==>  Preparing: select id,name,age from user where id= ?

2017-11-27 22:59:21,676 [main] DEBUG mybatis.com.tianshouzhi.mybatis.quickstart.mapper.UserMapper.testResultMap  - ==> Parameters: 1(Integer)

可以看到,所有的logger的名字前面,都有一个mybatis前缀。

1.2.3 3.0.6

这两个版本之间,mybatis日志实现处于过度阶段,因此同时兼容以上两种配置。需要注意的是,logImpl和logPrefix从3.2.0版本才开始支持,因此如果3.0.6

2 不同日志框架的配置

2.1 log4j配置

pom.xml中引入以下依赖

log4j

log4j

1.2.17

org.slf4j

slf4j-api

1.7.25

org.slf4j

slf4j-log4j12

1.7.25

其中slf4j和slf4j-log4j12是用于桥接用的,可以不引入。但是如果想用log4j作为日志框架,且项目中依赖了slf4j,就一定要引入slf4j-log4j12。

log4j.properties# 设置root logger日志打印级别为INFO,日志输出到STDOUT这个appender中

log4j.rootLogger=INFO,STDOUT

# 定义stdout这个STDOUT,其实现类为ConsoleAppender.表示日志输出到控制台中,读者可以使用其他appender,如DailyRollingFileAppender

log4j.appender.STDOUT=org.apache.log4j.ConsoleAppender

log4j.appender.STDOUT.layout=org.apache.log4j.PatternLayout

log4j.appender.STDOUT.layout.ConversionPattern=%d [%t] %-5p %c %x - %m%n

#设置mybatis打印sql日志

################### mybatis<=3.0.6 ##########################

#logger名称以java.sql为前缀

log4j.logger.java.sql=DEBUG

#################################################################

################### 3.0.6

#1、兼容3.0.6之间的配置

#2、且支持logger名称由namespace.id组成,这里的"com.tianshouzhi.mybatis"是namespace的公共前缀,读者自行修改

#log4j.logger.com.tianshouzhi.mybatis=DEBUG

#################################################################

################### mybatis>3.2.0 #######################

#1、支持logger名称由namespace.id组成

#2、支持在元素中配置logPrefix,例如这里配置了logPrefix的值为"mybatis.",则可以按照如下方式配置logger

#log4j.logger.mybatis=DEBUG

#################################################################

2.2 log4j2配置

mybatis在3.2.3之前,并不直接支持log4j2作为日志框架,必须通过slf4j或者commons-logging来做桥接。

3.2.3之后,支持直接使用log4j2,也就是可以在元素中通过配置logImpl值为LOG4J2,不过这种方式存在一个bug,直到mybatis 3.2.8版本才修复,参见:https://github.com/mybatis/mybatis-3/issues/234。

为了避免这些问题,在使用log4j2作为日志框架的话,建议直接使用slf4j做桥接。

org.slf4j

slf4j-api

1.7.25

org.apache.logging.log4j

log4j-slf4j-impl

2.3

org.apache.logging.log4j

log4j-api

2.3

org.apache.logging.log4j

log4j-core

2.3

log4j2.xml<?xml  version="1.0" encoding="UTF-8"?>

2.3 logback配置

mybatis并不支持直接使用logback作为日志框架, 如果要使用logback的话,必须使用slf4j做桥接。pom中引入如下依赖:

org.slf4j

slf4j-api

1.7.25

ch.qos.logback

logback-core

1.1.7

ch.qos.logback

logback-classic

1.1.7

logback.xml<?xml  version="1.0" encoding="UTF-8"?>

System.out

%d-[TS] %p %t %c - %m%n

2.4 jdk logging

笔者在实际项目开发中,并没有直接使用过jdk logging,其他三种都使用过。jdk logging是jdk自带的日志框架实现,位于java.util.logging包中。读者可以自行参照前面几种配置方式来配置jdk logging。

3 项目中存在多种日志框架的情况

有的读者可能会发现,即使按照上面的配置无误了,依然无法打印出日志。这是可能是项目中存在多种日志框架的jar包依赖,导致冲突。

默认情况下,mybatis按照如下方式检测需要使用的日志框架实现:

slf4j-->commons-logging-->log4j2-->log4j-->jdk logging(jul)-->no logging

在3.4.0 mybatis的org.apache.ibatis.logging.LogFactory类的源码中体现了上面的描述:

其中slf4j,commons-logging都是facade设计模式的实现,底层需要依赖具体的日志框架,如log4j、log4j2、logback等。并且还要引入相应的桥接jar包依赖。如果项目中有多种日志框架jar包依赖,可能会出现打印不了sql的情况,举例来说:

1、项目中有了slf4j依赖,那么mybatis就使用slf4j来打印日志,但是slf4j需要依赖具体的日志框架实现和桥接jar包,如果缺少,则不能正常工作。如项目中有了slf4j依赖,有了log4j依赖,但是缺少slf4j-log4j12桥接jar包,即使log4.properties配置正确也是无法打印sql日志的,读者可以自行尝试。

2、slf4j在检测底层日志框架实现时,最优先使用的是logback,如果项目中同时存在了logback的依赖,和log4j的依赖,即使用户正确配置了log4j.properties文件,由于slf4j选择使用了logback来打印日志,因此也无法打印出sql,读者可以自行尝试。

对于这种日志框架jar包依赖缺少或者冲突的情况,mybatis从3.2.0提供了一个终极解决方案,通过logImpl配置来强制指定使用哪个日志框架,使用方式如下所示:

logImpl的取值范围:SLF4J | LOG4J | LOG4J2 | JDK_LOGGING | COMMONS_LOGGING | STDOUT_LOGGING | NO_LOGGING

其中,STDOUT_LOGGING表示打印日志到控制台。NO_LOGGING表示不打印日志。

下面这张图列表出了slf4j在和各种底层日志框架如何整合,以及相应的需要引入的桥接jar包,这张图位于slf4j官网上:https://www.slf4j.org/manual.html

4 mybatis打印SQL日志最佳实践

一般在生产环境中应用系统,日志级别调整为INFO或者WARN以避免过多的输出日志。但某些时候,需要跟踪具体问题,那么就得打开DEBUG日志。但是如果设置root logger为DEBUG级别,则需要的信息就会淹没在日志的海洋中。

此时,需要单独指定某个或者某些logger(如mybatis打印sql的logger)的日志级别为DEBUG,而root logger保持INFO或WARN不变。

细心的读者会发现,笔者在上面列出的log4j、log4j2、logback日志文件的配置时,都是将root logger配置为INFO级别,单独将mybatis打印sql的logger设置为了DEBUG级别。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值