MyBatis 常见日志组件集成详解
1. MyBatis 日志系统概述
MyBatis 内置了日志接口,可以自动集成多种流行的日志框架。它会按以下顺序查找日志实现:
- SLF4J
- Apache Commons Logging
- Log4j 2
- Log4j
- JDK logging
2. 主流日志组件集成
2.1 SLF4J + Logback(推荐)
依赖配置
<!-- Maven 依赖 -->
<dependencies>
<!-- SLF4J API -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>2.0.6</version>
</dependency>
<!-- Logback 实现 -->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.4.5</version>
</dependency>
<!-- MyBatis -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.11</version>
</dependency>
</dependencies>
Logback 配置文件
<!-- src/main/resources/logback.xml -->
<configuration>
<!-- 控制台输出 -->
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<!-- MyBatis SQL 日志配置 -->
<logger name="com.example.mapper" level="DEBUG" />
<!-- 显示执行的SQL语句和参数 -->
<logger name="java.sql.Connection" level="DEBUG"/>
<logger name="java.sql.Statement" level="DEBUG"/>
<logger name="java.sql.PreparedStatement" level="DEBUG"/>
<logger name="java.sql.ResultSet" level="DEBUG"/>
<!-- MyBatis 日志 -->
<logger name="org.apache.ibatis" level="INFO"/>
<!-- 根日志级别 -->
<root level="INFO">
<appender-ref ref="CONSOLE" />
</root>
</configuration>
2.2 Log4j2
依赖配置
<!-- Maven 依赖 -->
<dependencies>
<!-- Log4j2 -->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.19.0</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.19.0</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-slf4j-impl</artifactId>
<version>2.19.0</version>
</dependency>
</dependencies>
Log4j2 配置文件
<!-- src/main/resources/log4j2.xml -->
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN">
<Appenders>
<Console name="Console" target="SYSTEM_OUT">
<PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
</Console>
<!-- 文件输出 -->
<File name="MyFile" fileName="logs/mybatis.log">
<PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
</File>
</Appenders>
<Loggers>
<!-- MyBatis Mapper 接口的SQL日志 -->
<Logger name="com.example.mapper" level="DEBUG" additivity="false">
<AppenderRef ref="Console"/>
<AppenderRef ref="MyFile"/>
</Logger>
<!-- SQL 执行日志 -->
<Logger name="java.sql" level="DEBUG"/>
<Logger name="org.apache.ibatis" level="INFO"/>
<Root level="INFO">
<AppenderRef ref="Console"/>
</Root>
</Loggers>
</Configuration>
2.3 Log4j
依赖配置
<!-- Maven 依赖 -->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
Log4j 配置文件
# src/main/resources/log4j.properties
# 根日志级别
log4j.rootLogger=INFO, stdout
# 控制台输出
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n
# MyBatis SQL 日志
log4j.logger.com.example.mapper=DEBUG
log4j.logger.java.sql.Connection=DEBUG
log4j.logger.java.sql.Statement=DEBUG
log4j.logger.java.sql.PreparedStatement=DEBUG
log4j.logger.java.sql.ResultSet=DEBUG
2.4 标准输出(StdOut)日志
在 MyBatis 配置中启用
<!-- mybatis-config.xml -->
<configuration>
<settings>
<!-- 使用标准输出日志 -->
<setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>
</configuration>
3. Spring Boot 中的日志配置
3.1 Spring Boot + Logback(默认)
# application.properties
# MyBatis Mapper 日志级别
logging.level.com.example.mapper=DEBUG
# SQL 相关日志
logging.level.java.sql.Connection=DEBUG
logging.level.java.sql.Statement=DEBUG
logging.level.java.sql.PreparedStatement=DEBUG
# MyBatis 框架日志
logging.level.org.mybatis=INFO
logging.level.org.apache.ibatis=INFO
# 日志文件输出
logging.file.name=logs/myapp.log
logging.pattern.console=%d{yyyy-MM-dd HH:mm:ss} - %msg%n
logging.pattern.file=%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n
3.2 Spring Boot + Log4j2
<!-- pom.xml 中排除默认日志,引入 Log4j2 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j2</artifactId>
</dependency>
# application.yml
logging:
level:
com.example.mapper: DEBUG
java.sql: DEBUG
config: classpath:log4j2.xml
4. 日志输出效果示例
4.1 SQL 执行日志示例
2023-10-01 14:30:25.123 [http-nio-8080-exec-1] DEBUG c.e.m.UserMapper.selectById - ==> Preparing: SELECT * FROM users WHERE id = ?
2023-10-01 14:30:25.124 [http-nio-8080-exec-1] DEBUG c.e.m.UserMapper.selectById - ==> Parameters: 1(Long)
2023-10-01 14:30:25.126 [http-nio-8080-exec-1] DEBUG c.e.m.UserMapper.selectById - <== Total: 1
4.2 详细 SQL 日志配置
<!-- 更详细的 SQL 日志配置 -->
<logger name="com.example.mapper" level="TRACE"/>
<logger name="java.sql" level="TRACE"/>
5. 高级日志配置技巧
5.1 按环境配置不同的日志级别
<!-- logback-spring.xml -->
<springProfile name="dev">
<logger name="com.example.mapper" level="DEBUG"/>
<logger name="java.sql" level="DEBUG"/>
</springProfile>
<springProfile name="prod">
<logger name="com.example.mapper" level="WARN"/>
<logger name="java.sql" level="WARN"/>
</springProfile>
5.2 SQL 执行时间监控
// 自定义拦截器监控 SQL 执行时间
@Intercepts({@Signature(type = StatementHandler.class, method = "query", args = {Statement.class, ResultHandler.class})})
public class SqlExecuteTimeInterceptor implements Interceptor {
@Override
public Object intercept(Invocation invocation) throws Throwable {
long startTime = System.currentTimeMillis();
try {
return invocation.proceed();
} finally {
long endTime = System.currentTimeMillis();
long executeTime = endTime - startTime;
// 记录执行时间过长的 SQL
if (executeTime > 1000) {
Logger logger = LoggerFactory.getLogger("SLOW_SQL");
logger.warn("Slow SQL detected, execution time: {}ms", executeTime);
}
}
}
}
6. 常见问题与解决方案
6.1 日志冲突问题
<!-- 解决日志框架冲突 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
6.2 日志不输出问题排查
// 检查日志配置
public class LogConfigChecker {
public static void main(String[] args) {
// 检查所有日志框架
LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory();
StatusPrinter.print(lc);
// 测试日志输出
Logger logger = LoggerFactory.getLogger(LogConfigChecker.class);
logger.debug("Debug message");
logger.info("Info message");
}
}
6.3 生产环境日志配置
<!-- 生产环境日志配置 -->
<configuration>
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>logs/mybatis.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>logs/mybatis.%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<maxHistory>30</maxHistory>
<totalSizeCap>3GB</totalSizeCap>
</rollingPolicy>
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<!-- 生产环境只记录 WARN 级别以上的日志 -->
<root level="WARN">
<appender-ref ref="FILE"/>
</root>
<!-- 但 MyBatis SQL 日志仍然记录 DEBUG -->
<logger name="com.example.mapper" level="DEBUG"/>
</configuration>
7. 最佳实践总结
- 开发环境:使用 SLF4J + Logback,开启 DEBUG 级别 SQL 日志
- 生产环境:关闭 DEBUG 日志,使用文件输出,定期归档
- 日志级别:
- Mapper 接口:DEBUG(查看 SQL)
- java.sql 包:DEBUG(查看参数和结果)
- org.apache.ibatis:INFO 或 WARN
- 性能考虑:生产环境避免输出过多 DEBUG 日志
- 安全考虑:确保日志中不记录敏感信息(如密码)
通过合理配置日志组件,可以有效地监控 MyBatis 的 SQL 执行情况,便于调试和性能优化。