了解下mybatis日志机制

知其然,知其所以然。才是考量对一切事物是否真正理解了的一个重要指标。

众所周知,Mybatis具有以下特性。
①XML与注解两种形式手写SQL(半自动化可以).
②插件机制(可拓展形式加分页,SQL性能监控等)。
③日志,缓存(一级缓存,二级缓存)。

日志简介

日志可以用来记录,跟踪,排查等作用,在JAVA中,提供了Log4j,LogBack,JDKLog(典型的就是System.out),SLf4j(适配所有日志形式)这些日志形式。

使用到了哪些设计模式?

代理,工厂。

来看看ProxyLogger类图。


代理Logger.png

①:ConnectionLogger代理java.sql.Connection

②:PreparedStatementLogger代理java.sql.PreparedStatement

③:ResultSetLogger代理java.sql.ResultSet

④:StatementLogger代理java.sql.Statement

这四个类都继承了BaseJdbcLogger并实现了java.lang.reflect.InvocationHandler接口。

日志调用代码分析

ConnectionLogger提供一个newInstance来创建代理

  public static Connection newInstance(Connection conn, Log statementLog, int queryStack) {
    InvocationHandler handler = new ConnectionLogger(conn, statementLog, queryStack);
    ClassLoader cl = Connection.class.getClassLoader();
   //代理
    return (Connection) Proxy.newProxyInstance(cl, new Class[]{Connection.class}, handler);
  }

public Object invoke(Object proxy, Method method, Object[] params)
      throws Throwable {
    try {
      if (Object.class.equals(method.getDeclaringClass())) {
        return method.invoke(this, params);
      }    
     //执行java.sql.Connection#prepareStatement时使用PreparedStatementLogger代理
      if ("prepareStatement".equals(method.getName())) {
        if (isDebugEnabled()) {
          debug(" Preparing: " + removeBreakingWhitespace((String) params[0]), true);
        }        
        PreparedStatement stmt = (PreparedStatement) method.invoke(connection, params);
        stmt = PreparedStatementLogger.newInstance(stmt, statementLog, queryStack);
        return stmt;
      } 
    //执行java.sql.Connection#prepareCall{存储过程}时使用PreparedStatementLogger代理
else if ("prepareCall".equals(method.getName())) {
        if (isDebugEnabled()) {
          debug(" Preparing: " + removeBreakingWhitespace((String) params[0]), true);
        }        
        PreparedStatement stmt = (PreparedStatement) method.invoke(connection, params);
        stmt = PreparedStatementLogger.newInstance(stmt, statementLog, queryStack);
        return stmt;
      } 
    //执行java.sql.Connection#createStatement时使用StatementLogger代理

else if ("createStatement".equals(method.getName())) {
        Statement stmt = (Statement) method.invoke(connection, params);
        stmt = StatementLogger.newInstance(stmt, statementLog, queryStack);
        return stmt;
      } else {
        return method.invoke(connection, params);
      }
    } catch (Throwable t) {
      throw ExceptionUtil.unwrapThrowable(t);
    }
  }

BaseExecutor#getConnection中提供一个获得Connection的方法

Connection connection = transaction.getConnection();
   //Debug模式情况下才开启Connection代理模式
    if (statementLog.isDebugEnabled()) {
      return ConnectionLogger.newInstance(connection, statementLog, queryStack);
    } else {
      //不是Debugger模式直接返回原生connection
      return connection;
    }

MappedStatement#Builder中用Logfactory工厂根据MappedStatementId创建了一个Logger。

 line76-line80
    String logId = id;
      if (configuration.getLogPrefix() != null) {
        logId = configuration.getLogPrefix() + id;
      }
      mappedStatement.statementLog = LogFactory.getLog(logId);

如何开启MB日志机制

配置形式:
<configuration>
<settings>
<setting name="logImpl" value="STDOUT_LOGGING" />
</settings>
</configuration>
代码形式:
Configuration#setLogImpl(Class<? extends Log> logImpl)
//配置自己的log{
if (logImpl != null) {
this.logImpl = logImpl;
LogFactory.useCustomLogging(this.logImpl);
}
}

Configuration中预设了一些内部日志形式,以别名形式使用。

typeAliasRegistry.registerAlias("SLF4J", Slf4jImpl.class);
typeAliasRegistry.registerAlias("COMMONS_LOGGING", JakartaCommonsLoggingImpl.class);
typeAliasRegistry.registerAlias("LOG4J", Log4jImpl.class);
typeAliasRegistry.registerAlias("LOG4J2", Log4j2Impl.class);
typeAliasRegistry.registerAlias("JDK_LOGGING", Jdk14LoggingImpl.class);
typeAliasRegistry.registerAlias("STDOUT_LOGGING", StdOutImpl.class);
typeAliasRegistry.registerAlias("NO_LOGGING", NoLoggingImpl.class);

厚颜。
日志可以起到监控,分析排查问题等作用,不好的地方是消耗资源,拖慢速度,生产环境是禁用Debug模式的,而Mybatis设计上打印SQL日志只允许在Debug模式下被打印,设计上是很妙的。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • spring官方文档:http://docs.spring.io/spring/docs/current/spri...
    牛马风情阅读 5,708评论 0 3
  • 一、日志框架 市面上的日志框架有JUL、JCL、Jboss-logging、logback、Log4j、log4j...
    马斯克瑞德阅读 6,421评论 0 1
  • 1. 简介 1.1 什么是 MyBatis ? MyBatis 是支持定制化 SQL、存储过程以及高级映射的优秀的...
    笨鸟慢飞阅读 11,164评论 0 4
  • 在应用程序中添加日志记录总的来说基于三个目的:监视代码中变量的变化情况,周期性的记录到文件中供其他应用进行统计分析...
    时待吾阅读 10,437评论 0 6
  • 在应用程序中添加日志记录总的来说基于三个目的:监视代码中变量的变化情况,周期性的记录到文件中供其他应用进行统计分析...
    时待吾阅读 10,500评论 1 13