一、Log4j2
1、引入 Log4j2 依赖
<!-- log4j2依赖 -->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.17.1</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.17.1</version>
</dependency>
<!-- org.apache.ibatis.session.Configuration 会用上 -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.6</version>
</dependency>
2、添加 Log4j2.xml 文件
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="INFO">
<Appenders>
<Console name="Console" target="SYSTEM_OUT">
<PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n" />
</Console>
</Appenders>
<Loggers>
<!-- 打印SQL核心配置:将业务dao接口填写进去,并用控制台输出即可。"Console"为上面定义的 -->
<logger name="com.example.mapper" level="DEBUG" additivity="false">
<appender-ref ref="Console"/>
</logger>
<Root level="info">
<AppenderRef ref="Console" />
</Root>
</Loggers>
</Configuration>
3、实体类
package com.example.entity;
import java.io.Serializable;
public class User implements Serializable {
private Integer id;
private String name;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", name='" + name + '\'' +
'}';
}
}
4、Mapper
package com.example.mapper;
import com.example.entity.User;
import org.apache.ibatis.annotations.Select;
import java.util.List;
public interface UserMapper {
@Select("select id, name from t_user")
List<User> selectAllUsers();
}
5、Service
package com.example.service.impl;
import com.example.entity.User;
import com.example.mapper.UserMapper;
import com.example.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserMapper userMapper;
@Override
public List<User> selectAllUsers() {
return userMapper.selectAllUsers();
}
}
6、配置类
package com.example.log4j.config;
import org.apache.ibatis.logging.log4j2.Log4j2Impl;
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.sql.DataSource;
@Configuration
@ComponentScan("com.example")
@MapperScan("com.example.mapper")
public class AppConfiguration {
@Bean
public DataSource dataSource() {
DriverManagerDataSource driverManagerDataSource = new DriverManagerDataSource();
driverManagerDataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
driverManagerDataSource.setUrl("jdbc:mysql://192.168.0.118:3306/test");
driverManagerDataSource.setUsername("root");
driverManagerDataSource.setPassword("123456");
return driverManagerDataSource;
}
@Bean
public SqlSessionFactoryBean sqlSessionFactoryBean() throws Exception {
SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
// 核心代码 configuration.setLogImpl(Log4j2Impl.class);
org.apache.ibatis.session.Configuration configuration = new org.apache.ibatis.session.Configuration();
configuration.setLogImpl(Log4j2Impl.class);
sqlSessionFactoryBean.setConfiguration(configuration);
sqlSessionFactoryBean.setDataSource(dataSource());
return sqlSessionFactoryBean;
}
}
7、测试类
package com.example.test;
import com.example.config.AppConfiguration;
import com.example.pojo.UserPojo;
import com.example.service.impl.UserServiceImpl;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import java.util.List;
public class Test {
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
applicationContext.register(AppConfiguration.class);
applicationContext.refresh();
UserServiceImpl userServiceImpl = applicationContext.getBean(UserServiceImpl.class);
List<UserPojo> userPojoList = userServiceImpl.selectAllUserList();
userPojoList.forEach(System.out::println);
}
}
8、扩展
Log4j2第二种配置方式:
log4j2.xml + org.apache.ibatis.logging.LogFactory.useLog4J2Logging();
1、引入 mybatis 依赖
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.6</version>
</dependency>
2、需要一个log4j2.xml,下面为打印SQL的标签
<logger name="com.example.mapper" level="DEBUG" additivity="false">
<appender-ref ref="Console"/>
</logger>
3、在Spring容器初始化前设置一个日志对象,内部会自动将该对象赋值给全局变量 logConstructor
代码示例:
org.apache.ibatis.logging.LogFactory.useLog4J2Logging();
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
applicationContext.register(AppConfiguration.class);
applicationContext.refresh();
二、Log4j
1、引入 Log4j 依赖
<!-- Log4j -->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
<!-- 搭建环境需要的依赖(偷个懒,用的SpringBoot的依赖,可能会有冲突) -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<version>2.7.15</version>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.2.2</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.31</version>
</dependency>
2、添加 log4j.properties 文件
log4j.rootLogger=DEBUG,stdout
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=[%-5p] %d(%r) --> [%t] %l: %m %x %n
# 可打印出具体的结果,如下
log4j.logger.com.example.mapper=TRACE
# 具体日志打印内容如下:
# [DEBUG] 2024-02-29 22:49:19,942(67) --> [main] org.mybatis.logging.Logger.debug(Logger.java:49): Creating a new SqlSession
# [DEBUG] 2024-02-29 22:49:19,947(72) --> [main] org.mybatis.logging.Logger.debug(Logger.java:49): SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@4189d70b] was not registered for synchronization because synchronization is not active
# 22:49:19.953 [main] DEBUG org.springframework.jdbc.datasource.DataSourceUtils - Fetching JDBC Connection from DataSource
# 22:49:19.953 [main] DEBUG org.springframework.jdbc.datasource.DriverManagerDataSource - Creating new JDBC DriverManager Connection to [jdbc:mysql://192.168.0.118:3306/test]
# [DEBUG] 2024-02-29 22:49:20,684(809) --> [main] org.mybatis.logging.Logger.debug(Logger.java:49): JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@45792847] will not be managed by Spring
# [DEBUG] 2024-02-29 22:49:20,687(812) --> [main] org.apache.ibatis.logging.jdbc.BaseJdbcLogger.debug(BaseJdbcLogger.java:137): ==> Preparing: select id, name from t_user
# [DEBUG] 2024-02-29 22:49:20,702(827) --> [main] org.apache.ibatis.logging.jdbc.BaseJdbcLogger.debug(BaseJdbcLogger.java:137): ==> Parameters:
# [TRACE] 2024-02-29 22:49:20,713(838) --> [main] org.apache.ibatis.logging.jdbc.BaseJdbcLogger.trace(BaseJdbcLogger.java:143): <== Columns: id, name
# [TRACE] 2024-02-29 22:49:20,713(838) --> [main] org.apache.ibatis.logging.jdbc.BaseJdbcLogger.trace(BaseJdbcLogger.java:143): <== Row: 1, 张三
# [DEBUG] 2024-02-29 22:49:20,718(843) --> [main] org.apache.ibatis.logging.jdbc.BaseJdbcLogger.debug(BaseJdbcLogger.java:137): <== Total: 1
# [DEBUG] 2024-02-29 22:49:20,718(843) --> [main] org.mybatis.logging.Logger.debug(Logger.java:49): Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@4189d70b]
3、实体类
package com.example.entity;
import java.io.Serializable;
public class User implements Serializable {
private Integer id;
private String name;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", name='" + name + '\'' +
'}';
}
}
4、Mapper
package com.example.mapper;
import com.example.entity.User;
import org.apache.ibatis.annotations.Select;
import java.util.List;
public interface UserMapper {
@Select("select id, name from t_user")
List<User> selectAllUsers();
}
5、Service
package com.example.service.impl;
import com.example.entity.User;
import com.example.mapper.UserMapper;
import com.example.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserMapper userMapper;
@Override
public List<User> selectAllUsers() {
return userMapper.selectAllUsers();
}
}
6、配置类
package com.example.config;
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.sql.DataSource;
@Configuration
@ComponentScan("com.example")
@MapperScan("com.example.mapper")
public class AppConfiguration {
@Bean
public DataSource dataSource() {
DriverManagerDataSource driverManagerDataSource = new DriverManagerDataSource();
driverManagerDataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
driverManagerDataSource.setUrl("jdbc:mysql://192.168.0.118:3306/test");
driverManagerDataSource.setUsername("root");
driverManagerDataSource.setPassword("123456");
return driverManagerDataSource;
}
@Bean
public SqlSessionFactoryBean sqlSessionFactoryBean() {
SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
// 核心代码 configuration.setLogImpl(Log4jImpl.class);
org.apache.ibatis.session.Configuration configuration = new org.apache.ibatis.session.Configuration();
configuration.setLogImpl(Log4jImpl.class);
sqlSessionFactoryBean.setConfiguration(configuration);
sqlSessionFactoryBean.setDataSource(dataSource());
return sqlSessionFactoryBean;
}
}
7、测试类
package com.example.test;
import com.example.config.AppConfiguration;
import com.example.entity.User;
import com.example.service.impl.UserServiceImpl;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import java.util.List;
public class Test {
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
applicationContext.register(AppConfiguration.class);
applicationContext.refresh();
UserServiceImpl userServiceImpl = applicationContext.getBean(UserServiceImpl.class);
List<User> users = userServiceImpl.selectAllUsers();
users.forEach(System.out::println);
}
}
8、扩展
Log4j第二种配置方式与log4j2的第二种方式一致:
log4j.properties + org.apache.ibatis.logging.LogFactory.useLog4JLogging();
代码示例:
org.apache.ibatis.logging.LogFactory.useLog4JLogging();
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
applicationContext.register(AppConfiguration.class);
applicationContext.refresh();
三、自定义 Log 对象,实现 org.apache.ibatis.logging.Log 接口
1、自定义一个 Log 对象,实现 org.apache.ibatis.logging.Log 接口,重写接口下的方法
package com.example.log4j;
import org.apache.ibatis.logging.Log;
import java.util.logging.Logger;
public class CustomLog implements Log {
// 这里需要加上一个这种类型的构造器
// 不加直接报错:
// NoSuchMethodExcetpion: com.example.log.CustomLog.<init>(java.lang.String)
public CustomLog(String msg) {
}
/*
这里使用的 JUL 方式测试打印 mybatis 的 SQL ,因为 Mybatis 中会判断,日志对象是 Debug 级
别时才会打印 Mybatis 的 SQL,而 JUL 级别默认是 info 及以上的级别,所以
默认是打印不出 Mybatis 的 SQL 的,但我们自定义的可以稍微改动,使其用 JUL 打印 SQL。
*/
Logger logger = Logger.getLogger("jul");
// 源码中有许多判断日志级别的代码,为 debug 级别才打印,xxx.isDebugEnabled(),就是下面这个方法
@Override
public boolean isDebugEnabled() {
return true;
}
@Override
public boolean isTraceEnabled() {
return false;
}
@Override
public void error(String s, Throwable e) {
}
@Override
public void error(String s) {
}
// 如果是 debug 级别,外部就会调用 log.debug(s),就是执行下面这个方法
@Override
public void debug(String s) {
logger.info(s);
}
@Override
public void trace(String s) {
}
@Override
public void warn(String s) {
}
}
2、配置类
package com.example.log4j.config;
import org.apache.ibatis.logging.log4j2.Log4j2Impl;
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.sql.DataSource;
@Configuration
@ComponentScan("com.example")
@MapperScan("com.example.mapper")
public class AppConfiguration {
@Bean
public DataSource dataSource() {
DriverManagerDataSource driverManagerDataSource = new DriverManagerDataSource();
driverManagerDataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
driverManagerDataSource.setUrl("jdbc:mysql://192.168.0.118:3306/test");
driverManagerDataSource.setUsername("root");
driverManagerDataSource.setPassword("123456");
return driverManagerDataSource;
}
@Bean
public SqlSessionFactoryBean sqlSessionFactoryBean() throws Exception {
SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
// 核心代码 configuration.setLogImpl(CustomLog.class);
org.apache.ibatis.session.Configuration configuration = new org.apache.ibatis.session.Configuration();
// 这句代码底层就是调用 使用自定义Log对象 方法
configuration.setLogImpl(CustomLog.class);
sqlSessionFactoryBean.setConfiguration(configuration);
sqlSessionFactoryBean.setDataSource(dataSource());
return sqlSessionFactoryBean;
}
}
3、测试类
package com.example.test;
import com.example.config.AppConfiguration;
import com.example.entity.User;
import com.example.service.impl.UserServiceImpl;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import java.util.List;
public class Test {
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
applicationContext.register(AppConfiguration.class);
applicationContext.refresh();
UserServiceImpl userServiceImpl = applicationContext.getBean(UserServiceImpl.class);
// 调用下面方法会打印SQL
List<User> users = userServiceImpl.selectAllUsers();
users.forEach(System.out::println);
}
}
四、配置文件说明
1、log4j2.xml
// 打印日志核心配置
<logger name="com.example.mapper" level="DEBUG" additivity="false">
<appender-ref ref="Console"/>
</logger>
2、log4j.properties
// 打印日志核心配置
log4j.logger.com.example.mapper.UserMapper=DEBUG
/*
以上两个配置文件可以搭配setLogImpl方法使用,Mybatis的打印SQL功能也会生效
setLogImpl两种方式:
①代码方式:
configuration.setLogImpl(Log4j2Impl.class);
②mybatis-config.xml方式:
<configuration>
<settings>
...
<setting name="logImpl" value="LOG4J"/>
...
</settings>
</configuration>
这两种方式底层其实是调用了 LogFactory.useCustomLogging(this.logImpl); 方法,将传入的Log对象赋值给 全局的Log对象 logConstructor
若只有 setLogImpl 而没有 ① 和 ②,则在 org.apache.ibatis.executor.BaseExecutor 类中 getConnection(Log statementLog) 方法中无法通过 statementLog.isDebugEnabled() 校验,从而无法产生代理对象 org.apache.ibatis.logging.ConnectionLogger ,也就不能打印方法执行的SQL。
没通过 statementLog.isDebugEnabled() 校验时,Connection 对象为 JDBC4Connection,不打印SQL。
而自定义的 CustomLog 对象之所以能够打印 SQL 正是因为重写了 Log 接口中的 isDebugEnabled() 方法并始终返回 true,所以他也能够通过 statementLog.isDebugEnabled() 校验,并产生代理对象 org.apache.ibatis.logging.ConnectionLogger,从而实现打印方法执行的SQL功能。
所以,执行mapper接口方法时,打印出其SQL语句日志的条件为:
需要保证当前日志对象的 isDebugEnabled() 为 true 。
调试入口:
org.mybatis.spring.SqlSessionTemplate.SqlSessionInterceptor
Object result = method.invoke(sqlSession, args);