MyBatis 內置日誌工廠自動檢測類路徑中的日誌框架(優先級:SLF4J → Log4j2 → Log4j → JDK Logging → No Logging)。啟用 SQL 日誌需:
DEBUG 或 TRACE### 根日誌級別
log4j.rootLogger=INFO, stdout, file
### 控制台輸出
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.out
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5p %c{1}:%L - %m%n
### 文件輸出 (滾動)
log4j.appender.file=org.apache.log4j.RollingFileAppender
log4j.appender.file.File=logs/mybatis.log
log4j.appender.file.MaxFileSize=10MB
log4j.appender.file.MaxBackupIndex=10
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5p %c{1}:%L - %m%n
### 【關鍵】MyBatis SQL 日誌啟用
log4j.logger.org.apache.ibatis=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
### 可選:僅啟用特定 Mapper 的 SQL 日誌
# log4j.logger.com.example.mapper.UserMapper=TRACE
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN" monitorInterval="30">
<Appenders>
<Console name="Console" target="SYSTEM_OUT">
<PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{36}:%L - %msg%n"/>
</Console>
<RollingFile name="File" fileName="logs/mybatis.log" filePattern="logs/mybatis-%d{yyyy-MM-dd}.log.gz">
<PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{36}:%L - %msg%n"/>
<Policies>
<TimeBasedTriggeringPolicy interval="1" modulate="true"/>
<SizeBasedTriggeringPolicy size="10 MB"/>
</Policies>
<DefaultRolloverStrategy max="30"/>
</RollingFile>
</Appenders>
<Loggers>
<Root level="INFO">
<AppenderRef ref="Console"/>
<AppenderRef ref="File"/>
</Root>
<!-- 【關鍵】MyBatis SQL 日誌 -->
<Logger name="org.apache.ibatis" level="DEBUG" additivity="false">
<AppenderRef ref="Console"/>
<AppenderRef ref="File"/>
</Logger>
<Logger name="java.sql.Connection" level="DEBUG" additivity="false">
<AppenderRef ref="Console"/>
<AppenderRef ref="File"/>
</Logger>
<Logger name="java.sql.Statement" level="DEBUG" additivity="false">
<AppenderRef ref="Console"/>
<AppenderRef ref="File"/>
</Logger>
<Logger name="java.sql.PreparedStatement" level="DEBUG" additivity="false">
<AppenderRef ref="Console"/>
<AppenderRef ref="File"/>
</Logger>
<Logger name="java.sql.ResultSet" level="DEBUG" additivity="false">
<AppenderRef ref="Console"/>
<AppenderRef ref="File"/>
</Logger>
<!-- 可選:特定 Mapper -->
<!-- <Logger name="com.example.mapper" level="TRACE" additivity="false">...</Logger> -->
</Loggers>
</Configuration>
<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true" scanPeriod="30 seconds">
<property name="LOG_PATTERN" value="%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36}:%L - %msg%n"/>
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<encoder><pattern>${LOG_PATTERN}</pattern></encoder>
</appender>
<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}.log.gz</fileNamePattern>
<maxHistory>30</maxHistory>
</rollingPolicy>
<encoder><pattern>${LOG_PATTERN}</pattern></encoder>
</appender>
<root level="INFO">
<appender-ref ref="CONSOLE"/>
<appender-ref ref="FILE"/>
</root>
<!-- 【關鍵】MyBatis SQL 日誌 -->
<logger name="org.apache.ibatis" level="DEBUG" additivity="false">
<appender-ref ref="CONSOLE"/>
<appender-ref ref="FILE"/>
</logger>
<logger name="java.sql.Connection" level="DEBUG" additivity="false">
<appender-ref ref="CONSOLE"/>
<appender-ref ref="FILE"/>
</logger>
<logger name="java.sql.Statement" level="DEBUG" additivity="false">
<appender-ref ref="CONSOLE"/>
<appender-ref ref="FILE"/>
</logger>
<logger name="java.sql.PreparedStatement" level="DEBUG" additivity="false">
<appender-ref ref="CONSOLE"/>
<appender-ref ref="FILE"/>
</logger>
<logger name="java.sql.ResultSet" level="DEBUG" additivity="false">
<appender-ref ref="CONSOLE"/>
<appender-ref ref="FILE"/>
</logger>
</configuration>
logging:
level:
# MyBatis SQL 日誌
org.apache.ibatis: DEBUG
java.sql.Connection: DEBUG
java.sql.Statement: DEBUG
java.sql.PreparedStatement: DEBUG
java.sql.ResultSet: DEBUG
# 特定 Mapper (可選)
# com.example.mapper: TRACE
pattern:
console: "%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36}:%L - %msg%n"
file: "%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36}:%L - %msg%n"
file:
name: logs/application.log
logback:
rollingpolicy:
max-file-size: 10MB
max-history: 30
<settings>
<setting name="logImpl" value="SLF4J"/> <!-- 指定日誌實現:SLF4J/LOG4J/LOG4J2/JDK_LOGGING/STDOUT_LOGGING/NO_LOGGING -->
<setting name="logPrefix" value=""/> <-- 日誌前綴 -->
</settings>
| 級別 | 輸出內容 | 性能影響 | 建議環境 |
|---|---|---|---|
| ERROR | 錯誤堆棧 | 極低 | 生產 |
| WARN | 警告信息 | 極低 | 生產 |
| INFO | 啟動信息、緩存命中 | 低 | 生產 |
| DEBUG | SQL 語句、參數、結果集行數 | 中 | 開發/測試 |
| TRACE | DEBUG + 參數值詳細綁定、結果集數據 | 高 | 問題排查 |
生產環境嚴禁開啟 DEBUG/TRACE,會產生海量日誌、暴露敏感數據、嚴重影響性能。
DEBUG 級別下,PreparedStatement 參數以 ? 佔位。需完整看到實際 SQL:
<dependency>
<groupId>com.github.gavlyukovskiy</groupId>
<artifactId>p6spy-spring-boot-starter</artifactId>
<version>1.9.0</version>
</dependency>
# application.yml
decorator:
datasource:
p6spy:
enable-logging: true
multiline: true
logging: slf4j
輸出示例:
SELECT * FROM t_user WHERE id = 1 AND name = '張三' -- 完整實際 SQL,無佔位符
| 現象 | 原因 | 解決 |
|---|---|---|
| 無 SQL 日誌輸出 | Logger 級別未設為 DEBUG、日誌框架未正確初始化 | 檢查配置文件路徑、logImpl 設置、依賴衝突 |
| 日誌雙重輸出 | additivity="false" 未設置、Root Logger 也輸出 | Logger 設置 additivity="false" |
| 參數顯示為 ? | DEBUG 級別默認行為 | 用 TRACE 級別或 P6Spy/Druid |
| 生產環境性能下降 | 開啟了 DEBUG/TRACE | 生產僅 INFO/WARN,排查用 P6Spy 采樣 |
| 類加載器衝突 | 多日誌框架共存 (Log4j + Logback) | 排除傳遞依賴,統一 SLF4J + 一個實現 |
MyBatis SQL 日誌輸出核心:引入日誌實現 + 配置 org.apache.ibatis/java.sql.* Logger 為 DEBUG。主流框架 Log4j/Log4j2/Logback/Spring Boot 均支持。生產環境嚴禁開啟 DEBUG,排查慢 SQL/參數問題請用 P6Spy 或 Druid 監控。配置模板可直接複製適配項目,建議統一使用 SLF4J + Logback/Log4j2 作為日誌門面與實現。