Mybatis日志体系
承接上一篇关于spring 5.x的日志体系,本篇看看Mybatis的日志体系及实现,Mybatis版本基于3.x。
关于mybatis的官方文档比较友好,分门别类,各有论述,如mybatis官方文档详见https://mybatis.org/mybatis-3/#,mybatis与spring的官方文档详见http://mybatis.org/spring/index.html,与springboot相关的参见http://mybatis.org/spring-boot-starter/mybatis-spring-boot-autoconfigure/#,官方文档写的很完备,也适合初学者。
Mybatis环境搭建及日志展示
研究mybatis日志,有必要写一个demo,该有的数据库(Mysql)相关的jar包依赖都应该有,pom文件如下。
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.6</version>
</dependency> <dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>1.3.2</version>
</dependency> <dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
version>8.0.13</version>
</dependency> <dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.1.3.RELEASE</version>
</dependency> <dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.1.3.RELEASE</version>
</dependency>
配置mybatis环境:java config风格获取一个SqlSessionFactoryBean和动态动态注入一个数据源dataSource,连接本地的数据库company,表为user。
@Configuration
@ComponentScan("com.mystyle")
@MapperScan("com.mystyle.dao")
public class MybatisConfig {
@Bean
@Autowired
public SqlSessionFactoryBean sqlSessionFactory(DataSource dataSource) throws Exception {
SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
sqlSessionFactoryBean.setDataSource(dataSource);
// org.apache.ibatis.session.Configuration configuration = new org.apache.ibatis.session.Configuration();
// configuration.setLogImpl(Log4jImpl.class);
// sqlSessionFactoryBean.setConfiguration(configuration);
return sqlSessionFactoryBean;
} @Bean
public DataSource dataSource() {
DriverManagerDataSource driverManagerDataSource = new DriverManagerDataSource();
driverManagerDataSource.setUsername("root");
driverManagerDataSource.setPassword("12345678");
driverManagerDataSource.setUrl("jdbc:mysql://localhost:3306/company?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=UTC");
driverManagerDataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
return driverManagerDataSource; } }
注:注释的代码请先忽略,后续会用到。
写一个UserDao,查询出user表中的user信息
public interface UserDao {
@Select("select * from user")
List<Map<String,String>> queryUsers();
}
运行完成之后,可以看到console成功打印出了user的信息,但是除此之外,并未看到我们想要的打印出sql语句等信息。
Mybatis日志代码跟踪
在MybatisConfig的sqlSessionFactory方法中,new出了一个SqlSessionFactoryBean,在SqlSessionFactoryBean类中可以看到一个关于Logger的私有对象的声明并初始化。
public class SqlSessionFactoryBean implements FactoryBean<SqlSessionFactory>, InitializingBean, ApplicationListener<ApplicationEvent> {
private static final Log LOGGER = LogFactory.getLog(SqlSessionFactoryBean.class);
在LogFactory类中,
public final class LogFactory {
/**
* Marker to be used by logging implementations that support markers
*/
public static final String MARKER = "MYBATIS";
private static Constructor<? extends Log> logConstructor;
static {
//1.启动线程
tryImplementation(new Runnable() {
@Override
public void run() {
//2。加载日志类,返回构造器
useSlf4jLogging();
}
});
tryImplementation(new Runnable() {
@Override
public void run() {
useCommonsLogging();
}
});
tryImplementation(new Runnable() {
@Override
public void run() {
useLog4J2Logging();
}
});
tryImplementation(new Runnable() {
@Override
public void run() {
useLog4JLogging();
}
});
tryImplementation(new Runnable() {
@Override
public void run() {
useJdkLogging();
}
});
tryImplementation(new Runnable() {
@Override
public void run() {
useNoLogging();
}
});
}
private LogFactory() {
// disable construction
}
public static Log getLog(Class<?> aClass) {
return getLog(aClass.getName());
}
public static Log getLog(String logger) {
try {
return logConstructor.newInstance(logger);
} catch (Throwable t) {
throw new LogException("Error creating logger for logger " + logger + ". Cause: " + t, t);
}
}
public static synchronized void useCustomLogging(Class<? extends Log> clazz) {
setImplementation(clazz);
}
public static synchronized void useSlf4jLogging() {
setImplementation(org.apache.ibatis.logging.slf4j.Slf4jImpl.class);
}
public static synchronized void useCommonsLogging() {
setImplementation(org.apache.ibatis.logging.commons.JakartaCommonsLoggingImpl.class);
}
public static synchronized void useLog4JLogging() {
setImplementation(org.apache.ibatis.logging.log4j.Log4jImpl.class);
}
public static synchronized void useLog4J2Logging() {
setImplementation(org.apache.ibatis.logging.log4j2.Log4j2Impl.class);
}
public static synchronized void useJdkLogging() {
setImplementation(org.apache.ibatis.logging.jdk14.Jdk14LoggingImpl.class);
}
public static synchronized void useStdOutLogging() {
setImplementation(org.apache.ibatis.logging.stdout.StdOutImpl.class);
}
public static synchronized void useNoLogging() {
setImplementation(org.apache.ibatis.logging.nologging.NoLoggingImpl.class);
}
private static void tryImplementation(Runnable runnable) {
if (logConstructor == null) {
try {
runnable.run();
} catch (Throwable t) {
// ignore
}
}
}
private static void setImplementation(Class<? extends Log> implClass) {
try {
Constructor<? extends Log> candidate = implClass.getConstructor(String.class);
//3. 试图去实例化一个实现类的日志对象
Log log = candidate.newInstance(LogFactory.class.getName());
if (log.isDebugEnabled()) {
log.debug("Logging initialized using '" + implClass + "' adapter.");
}
logConstructor = candidate;
} catch (Throwable t) {
throw new LogException("Error setting Log implementation. Cause: " + t, t);
}
}
}
LogFactory在加载时,有一个静态代码块,会依次去加载各种日志产品的实现,请其中的顺序是 SLF4J > Apache Commons Logging > Log4j 2 > Log4j > JDK logging。
以SLF4J为例说明(其余类似):
- 执行tryImplementation方法:如果构造器logConstructor(LogFactory中的私有变量)不为空,启动一个线程去执行其中的run 方法。
- 具体是去执行useSlf4jLogging方法中的setImplementation方法,该方法会传入SLF4J的日志实现类的class对象:class org.apache.ibatis.logging.slf4j.Slf4jImpl。
- 试图去实例化一个实现类的日志对象,由于此时并未加入slf4j相关jar包依赖,所以会抛一个异常出去。
在默认情况下,即是用户未指定得情况下,class org.apache.ibatis.logging.commons.JakartaCommonsLoggingImpl也就是Apache Commons Logging会默认实例化成功,spring默认使用此日志实现,由于存在该实现依赖,所以会被实例化成功,并返回其构造器。SqlSessionFactoryBean中调用的getLog方法实际是返回了一个基于JCL实现的日志对象。
用户指定Mybatis日志实现类
假设用户需要使得Mybatis使用的日志是基于log4j的,同样,首先需要在pom中先添加基于log4j的相关依赖,log4j.properties配置文件添加,在sqlSessionFactoryBean实例化时通过configuration去手动指定logimpl为log4J。
public void setLogImpl(Class<? extends Log> logImpl) {
if (logImpl != null) {
this.logImpl = logImpl;
LogFactory.useCustomLogging(this.logImpl);
}
}
实际内部是去调用了LogFactory的useCustomLogging方法。
public static synchronized void useCustomLogging(Class<? extends Log> clazz) {
setImplementation(clazz);
}
其余和上述流程一样,把factory中的日志实现类更新为用户所指定的实现类。
日志打印效果
DEBUG - Logging initialized using 'class org.apache.ibatis.logging.log4j.Log4jImpl' adapter.
DEBUG - Creating a new SqlSession
DEBUG - SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@4716be8b] was not registered for synchronization because synchronization is not active
DEBUG - JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@3faf2e7d] will not be managed by Spring
DEBUG - ==> Preparing: select * from user
DEBUG - ==> Parameters:
DEBUG - <== Total: 7
DEBUG - Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@4716be8b]
[{eventId=1, count_num=1, name=tom, id=1}, {eventId=2, count_num=2, name=jack, id=2}, {eventId=7, count_num=2, name=david, id=3}, {eventId=3, count_num=2, name=david, id=4}, {eventId=4, count_num=0, name=david, id=5}, {eventId=5, count_num=1, name=david, id=6}, {eventId=6, count_num=0, name=lily, id=7}]
Disconnected from the target VM, address: '127.0.0.1:53155', transport: 'socket'
可以看到日志打印出的格式以及内容都是我们所想要的。
Mybatis日志体系的更多相关文章
- Mybatis日志源码探究
一.项目搭建 1.pom.xml <dependencies> <dependency> <groupId>log4j</groupId> <ar ...
- Oracle RAC的日志体系
Oracle Clusterware 不像数据库那样,有丰富的视图.工具可以用来辅助诊断,它的日志和trace文件是唯一的选择.但不像Oracle只有alert日志和几种trace文件,Oracle ...
- Oracle RAC环境的日志体系
转摘:http://blog.itpub.net/22664653/viewspace-722463/ 在Oracle RAC环境中比单个系统的日志体系要复杂:见下图: 简单介绍一下有关Oracle集 ...
- 笔记:MyBatis 日志显示-log4j2
在ClassPath路径创建log4j2.xml配置文件,增加如下日志配置: <?xml version="1.0" encoding="UTF-8"?& ...
- 【原创】架构师必备,带你弄清混乱的JAVA日志体系!
引言 还在为弄不清commons-logging-xx.jar.log4j-xx.jar.sl4j-api-xx.jar等日志框架之间复杂的关系而感到烦恼吗? 还在为如何统一系统的日志输出而感到不知所 ...
- java 日志体系目录
java 日志体系目录 1.1 java 日志体系(一)log4j1.log4j2.logback.jul.jcl.slf4j 1.2 java 日志体系(二)jcl 和 slf4j 2.1 java ...
- java 日志体系(四)log4j 源码分析
java 日志体系(四)log4j 源码分析 logback.log4j2.jul 都是在 log4j 的基础上扩展的,其实现的逻辑都差不多,下面以 log4j 为例剖析一下日志框架的基本组件. 一. ...
- java 日志体系(三)log4j从入门到详解
java 日志体系(三)log4j从入门到详解 一.Log4j 简介 在应用程序中添加日志记录总的来说基于三个目的: 监视代码中变量的变化情况,周期性的记录到文件中供其他应用进行统计分析工作: 跟踪代 ...
- Java 日志体系(二)jcl 和 slf4j
Java 日志体系(二)jcl 和 slf4j <java 日志体系(一)统一日志>:https://www.cnblogs.com/binarylei/p/9828166.html &l ...
随机推荐
- SQLServer执行大脚本文件时,提示“无法执行脚本没有足够的内存继续执行程序 (mscorlib)”
问题描述: 有时候服务器操作导入数据.sql,或者 当需求不可以直接备份整库还原时,往往通过导出数据库脚本的方式来部署-还原数据库表 但是当数据库导出脚本很大,用Microsoft SQL Serve ...
- MySQL计划任务(事件调度器)
原文:http://www.cnblogs.com/c840136/articles/2388512.html 备忘; MySQL5.1.x版本中引入了一项新特性EVENT,顾名思义就是事件.定时任务 ...
- kali linux 开启配置ssh服务
1. 一.配置SSH参数 修改sshd_config文件,命令为: vi /etc/ssh/sshd_config 将#PasswordAuthentication no的注释去掉,并且将NO修 ...
- 面经-VIVO
面试时间:2019.09.26 现场面试 面试岗位:广告推荐算法工程师/一面/正式批 面试时长:50Min 面试内容: 自我介绍 阶乘与阶乘和(复杂度高) 文本-视频论文讲解 视频排序讲解 概率题(2 ...
- Weed:线段树
观察复杂度,是log级别以下回答询问的. O(1)?逗我kx呢? 自然而然地想到线段树. 学长讲的原题啊考场上还不会打. 线段树上的每个节点都表示一个操作区间. 线段树上维护的权值有3个:这个子区间一 ...
- docker安装制定版本-centos7
# 安装依赖包 yum install -y yum-utils device-mapper-persistent-data lvm2 # 添加Docker软件包源 yum-config-manage ...
- csps63总结
这次考试还算可以(吧),暴力都没打满,但是还差很多. T1 强烈推荐我的打法,很好理解并且很好打(虽然稍长) 维护指针指向的值及其是第几个数,然后分类讨论. (诡异构造的序列==随机数据)?? #in ...
- P2114 [NOI2014]起床困难综合症
#include<iostream> #include<cstdio> using namespace std; ; ]; long long n,m; long long t ...
- 运维自动化管理服务器 CheungSSH
CheungSSH 是一款中国人自主研发的Linux运维自动化管理服务器软件,后端使用 Python 语言+Django 的 Web 框架,前端使用 Bootstrap+Javascript+jQue ...
- 面试开挂:近百道Java面试题整理
1.什么是Java虚拟机?为什么Java被称作是“平台无关的编程语言”? Java虚拟机是一个可以执行Java字节码的虚拟机进程.Java源文件被编译成能被Java虚拟机执行的字节码文件. Java被 ...