-
前言
博主在刚开始做开发的,对于mybatis如何打印sql完全不理解,看到网上全是通过xml来配置打印sql,因为之前博主全是使用javaConfig配置mybatis信息,所以觉得为了打印sql加单独加一个配置文件十分的麻烦,网上大部分又是千篇一律的推荐使用xml,所以博主就在官网找不依赖配置文件打印sql的方法,现在分享给大家。
-
正文
我们直接看mybatis官网:
可以看到,mybatis第一个推荐使用的就是xml,但是这显然不是博主想要的答案,所以,继续往下看:
可以看到,mybatis提供了不使用配置文件的方法打印sql,接下来我们就来看看,怎么在不使用xml的前提下打印sql。
方法一:
使用官网推荐的org.apache.ibatis.logging.LogFactory.useLog4JLogging(),在spring容器初始化之前,调用这个方法,让mybatis使用log4j打印sql:
import org.apache.ibatis.logging.log4j.Log4jImpl;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import javax.annotation.PostConstruct;
import javax.sql.DataSource;
@Configuration
@ComponentScan("com.cht")
@MapperScan("com.cht.dao")
public class AppConfig {
@PostConstruct
public void init(){
org.apache.ibatis.logging.LogFactory.useLog4JLogging();
}
@Bean
public DataSource dataSource(){
DriverManagerDataSource driverManagerDataSource = new DriverManagerDataSource();
driverManagerDataSource.setDriverClassName("com.mysql.jdbc.Driver");
driverManagerDataSource.setUsername("tzgdev");
driverManagerDataSource.setPassword("123456");
driverManagerDataSource.setUrl("jdbc:mysql://192.168.4.12:3306/tzgdev?useUnicode=true&characterEncoding=UTF-8");
return driverManagerDataSource;
}
@Bean
public SqlSessionFactoryBean sqlSessionFactoryBean(){
SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
/*org.apache.ibatis.session.Configuration configuration = new org.apache.ibatis.session.Configuration();
configuration.setLogImpl(Log4jImpl.class);*/
sqlSessionFactoryBean.setDataSource(dataSource());
return sqlSessionFactoryBean;
}
}
为什么调用这个方法就可以打印sql了呢?我们来看下源码,我们打开org.apache.ibatis.logging.LogFactory,可以看到这个类当中有一段静态代码块:
static {
tryImplementation(new Runnable() {
public void run() {
LogFactory.useSlf4jLogging();
}
});
tryImplementation(new Runnable() {
public void run() {
LogFactory.useCommonsLogging();
}
});
tryImplementation(new Runnable() {
public void run() {
LogFactory.useLog4J2Logging();
}
});
tryImplementation(new Runnable() {
public void run() {
LogFactory.useLog4JLogging();
}
});
tryImplementation(new Runnable() {
public void run() {
LogFactory.useJdkLogging();
}
});
tryImplementation(new Runnable() {
public void run() {
LogFactory.useNoLogging();
}
});
}
在当中run了6个方法,我们来看第一个run()方法:
private static void setImplementation(Class<? extends Log> implClass) {
try {
Constructor<? extends Log> candidate = implClass.getConstructor(String.class);
Log log = (Log)candidate.newInstance(LogFactory.class.getName());
if (log.isDebugEnabled()) {
log.debug("Logging initialized using '" + implClass + "' adapter.");
}
logConstructor = candidate;
} catch (Throwable var3) {
throw new LogException("Error setting Log implementation. Cause: " + var3, var3);
}
}
public static Log getLog(String logger) {
try {
return (Log)logConstructor.newInstance(logger);
} catch (Throwable var2) {
throw new LogException("Error creating logger for logger " + logger + ". Cause: " + var2, var2);
}
}
可以看到,mybatis通过不同的类,去反射得到不同的日志对象,再来看tryImplementation()这个方法:
private static void tryImplementation(Runnable runnable) {
if (logConstructor == null) {
try {
runnable.run();
} catch (Throwable var2) {
}
}
}
可以看到当实例化出来一个日志对象之后,就不会调用run()方法了,看到这里,大家肯定觉得奇怪,如果是这样,那之前加了log4j依赖不就可以直接打印sql了吗?这其实这是mybatis整合spring5的一个坑,spring5使用的是spring-jcl,所以会跑第二个run()方法,但是jcl默认是使用jul的,并且不支持log4j只支持log4j2(不懂的童鞋可以去看博主上一篇文章--spring5日志新特性详解),那为什么用jul无法打印sql呢?看源码可以知道,jcl底层的日志级别是FINE,而我们在log.properties中用的是DEBUG级别,所以当整合spring跟myBatis的时候,只引入log4j包的话是不能打印sql的。
方法二:
在实例化sqlSessionFactory的时候,调用LogFactory的useCustomLogging()方法,跟xml的使用注解的方式一样:
import org.apache.ibatis.logging.log4j.Log4jImpl;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import javax.annotation.PostConstruct;
import javax.sql.DataSource;
@Configuration
@ComponentScan("com.cht")
@MapperScan("com.cht.dao")
public class AppConfig {
/*@PostConstruct
public void init(){
org.apache.ibatis.logging.LogFactory.useLog4JLogging();
}*/
@Bean
public DataSource dataSource(){
DriverManagerDataSource driverManagerDataSource = new DriverManagerDataSource();
driverManagerDataSource.setDriverClassName("com.mysql.jdbc.Driver");
driverManagerDataSource.setUsername("tzgdev");
driverManagerDataSource.setPassword("123456");
driverManagerDataSource.setUrl("jdbc:mysql://192.168.4.12:3306/tzgdev?useUnicode=true&characterEncoding=UTF-8");
return driverManagerDataSource;
}
@Bean
public SqlSessionFactoryBean sqlSessionFactoryBean(){
SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
org.apache.ibatis.session.Configuration configuration = new org.apache.ibatis.session.Configuration();
configuration.setLogImpl(Log4jImpl.class);
sqlSessionFactoryBean.setDataSource(dataSource());
return sqlSessionFactoryBean;
}
}
可以看到博主在实例化sqlSessionFactory的时候,调用了这段代码:
org.apache.ibatis.session.Configuration configuration = new org.apache.ibatis.session.Configuration();
configuration.setLogImpl(Log4jImpl.class);
那么这个方法是干嘛的呢?我们来看源码:
public void setLogImpl(Class<? extends Log> logImpl) {
if (logImpl != null) {
this.logImpl = logImpl;
LogFactory.useCustomLogging(this.logImpl);
}
}
public static synchronized void useCustomLogging(Class<? extends Log> clazz) {
setImplementation(clazz);
}
可以看到博主通过这个方法传了log4j类进去,给logConstructor赋了log4j的构造方法,这样logConstructor不为空,所以也不会去创建其他日志对象,当然直接调用LogFactory.useCustomLogging(Log4jImpl.class)或org.apache.ibatis.logging.LogFactory.useLog4JLogging()也一样:
综上就是博主自己研究的mybatis不依靠xml实现打印sql日志的方法,希望对大家有所帮助。