关于mybatis怎么打印出sql这个问题,可以百度一下,很多答案都有类似这样的答案:
就是把java.sql.*,com.ibatis等的日志级别都配置成debug的,也许这么配置与默认的info配置相比真的有效果,把sql打印出来了。可是我今天才发现,打印sql与这些java.sql,com.ibatis包半毛钱关系都没有。至少我调试的mybatis-3.3.0.jar就是这样的,因为它打印日志的对象是org.apache.ibatis.logging.slf4j.Slf4jImpl(statementLog),而statementLog又是在系统启动时,扫描的logId(如com.**.Mapper.query)作为其构造参数的。是否打印日志就是这个参数是否与log4j.xml,与log4j.properties里的log4j.logger匹配来决定的。下面通过源码来分析整个过程:
1.statementLog是否为debug,来决定是否打印sql
代码:org.apache.ibatis.executor.SimpleExecutor
如果进入上图里创建ConnectionLogger对象的代码,就可执行真正打印日志的代码。如下图
类:org.apache.ibatis.logging.jdbc.BaseJdbcLogger
代码行:ConnectionLogger(BaseJdbcLogger).debug(String, boolean) line: 141
2.statementLog的注入
statementLog来源于MappendStatement
而MappendStatement是org.apache.ibatis.session.Configuration注册进去的。
再看MappendStatement的构造过程是如何创建Log的。
类:org.apache.ibatis.mapping.MappedStatement.Builder
LogFactory.getLog(xx)这行代码再熟悉不过了吧,从这里的值来看,是不是跟什么java.sql、com.ibatis没有半毛钱关系。
mybatis用的日志框架确实足够强大,无论我们是用slf4j还是common-logger,它都能用起来,这是什么么呢?
看下类:org.apache.ibatis.logging.LogFactory:
在加载这个类时会执行上面的静态代码块,这里会依次去尝试各种日志框架的实现。尝试代码如下:
如果有一个成功,则logConstructor就被实例化,不为空了,后面的就没有机会执行了。从这里的代码我又学了一招,怎么兼容客户端不同的jar实现,即使客户端没有其中的一个实现jar包,代码也不会错。
最后还是回答一下标题,如何打印sql呢,比如我上面的代码就配置一下log4j.logger.com.helijia.search=DEBUG,就可以了。