Mybatis 调试输出SQL语句,到底是如何实现的呢?

Java开发过程中几种常见日志框架种类繁多,且这些日志框架分别来自于不同开源组织,为用户揭露的界面存在诸多差异,因此许多开源框架都各自定义了一组统一日志界面并与前述第三方日志框架兼容以供高层参考。

在本文中,我们主要研究基于适配器模式的第三方日志框架接口的设计与实现,并将其作为一个独立的模块进行详细阐述,同时对其他一些常见的日志接口做了介绍。在这篇文章中我们要介绍一个新的通用的日志格式转换工具——My Batis,它可以方便地完成各种不同类型的日志格式转换。如果您有兴趣的话。本文中我们采用了My Batet来完成这个任务。

它的核心原理就是:以结合的形式把所需适配的类别转换为用户可以利用的界面。

MyBatis定制Log接口在org.apache.ibatis.logging数据包内,有关适配器在数据包内。

第一, LogFactory工厂类负责建立一个Log对象。LogFactory类具有一段静态代码块。每个第三方日志框架适配器将被顺序地装入。

static { tryImplementation(LogFactory::useSlf4jLogging); tryImplementation(LogFactory::useCommonsLogging); tryImplementation(LogFactory::useLog4J2Logging); tryImplementation(LogFactory::useLog4JLogging); tryImplementation(LogFactory::useJdkLogging); tryImplementation(LogFactory::useNoLogging); } 

以JDK Logging加载过程(useJdkLogging()方式)为例,具体代码实现及注释如下。

private static void tryImplementation(Runnable runnable) { if (logConstructor == null) { try { runnable.run(); } catch (Throwable t) { } } } public static synchronized void useJdkLogging() { setImplementation(org.apache.ibatis.logging.jdk14.Jdk14LoggingImpl.class); } private static void setImplementation(Class<? extends Log> implClass) { try { Constructor<? extends Log> candidate = implClass.getConstructor(String.class); Log log = candidate.newInstance(LogFactory.class.getName()); logConstructor = candidate; } catch (Throwable t) { throw new LogException(“Error setting Log implementation. Reason: “+ t, t);} 

下面展示Mybatis运行过程中如何输出SQL语句。具体的分析请参见原理章节

向mybatis.xml配置文件增加以下配置:

Byte

方法有2种,第1种同样使用StdOutImpl来达到类的目的来达到打印的目的。填入application.yml中的配置文件为:

#mybatis配置 mybatis: # 控制台打印sql日志 configuration: log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

第二,我们也可以在规定的日志级别上输出SQL语句:

SpringBoot预设采用SL4J+日志门面+Logback+具体实现日志组合

logging: level: xx包名: debug

下面就直接看org.apache、ibatis、executor、BaseExecutor、#getConnection等方法了,熟悉Mybatis应该知道Mybatis进行sql操作时是要访问数据库连接

protected Connection getConnection(Log statementLog) throws SQLException { Connection connection = transaction.getConnection(); if (statementLog.isDebugEnabled()) { return ConnectionLogger.newInstance(connection, statementLog, queryStack); } else { return connection; } }

可查看作者注释中的那一行,该行通过对日志级别进行判断以确定是否返回ConnectionLogger代理对象。然后在Log接口实现类StdOutImpl其isDebugEnabled实际上总是返回true.代码为

而其所直接使用的System.println则去了输出SQL信息

public class StdOutImpl implements Log { public boolean isDebugEnabled() { return true; } public boolean isTraceEnabled() { return true; } public void error(String s, Throwable e) { System.err.println(s); e.printStackTrace(System.err); } public void error(String s) { System.err.println(s); } }

至此至少您已经明白,为何我们会透过配置MyBatis所使用日志之特定执行logImpl,来达到将日志导出至控制台之功效。

那我们也可以深入探究statementLog何时成为StdOutImpl,当解析Mybatis的配置文件时,我们将去阅读我们所配置logImpl属性并通过LogFactory·useCustomLogging的方式首先指定适配器构建方式

private void loadCustomLogImpl(Properties props) { Classextends Log> logImpl = resolveClass(props.getProperty(“logImpl”)); configuration.setLogImpl(logImpl); } public void setLogImpl(Classextends Log> logImpl) { if (logImpl != null) { this.logImpl = logImpl; LogFactory.useCustomLogging(this.logImpl); } }

接着,当构造MappedStatement时,日志对象已初始化

每一个MappedStatement都对应着我们定制Mapper接口的一种方式,该接口保留着开发人员写好的SQL语句,参数结构和返回值结构以及Mybatis如何配置其处理方式等详细元素,这是一条SQL命令究竟为何物以及如何执行的完全定义。

public Builder(Configuration configuration, String id, SqlSource sqlSource, SqlCommandType sqlCommandType) { mappedStatement.statementLog = LogFactory.getLog(logId); mappedStatement.lang = configuration.getDefaultScriptingLanguageInstance(); } public static Log getLog(String logger) { try { return logConstructor.newInstance(logger); } catch (Throwable t) { throw new LogException(“Error creating logger for logger ” + logger + “. Reason: “+ t, t);}

最后,SpringBoot并没有概述

第一个途径实际上就是同理

另一种方法是在日志级别上进行修改后让isDebugEnabled回到true中并前往回到代理对象中再输出SQL语句。

有兴趣者也可查看SQL语句如何输出,具体地说就是ConnectionLogger公司invoke方法,就能找到耳熟能详的Preparing:“与”Parameters:“”。

原文链接:http://www.sfdkj.com/13369.html

© 版权声明
THE END
喜欢就支持一下吧
点赞10 分享
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

取消
昵称表情代码图片