MyBatis 內建日誌工廠自動適配 SLF4J、Log4j2、Log4j、JDK Logging、StdOut 等實現。本文詳細講解如何配置 Mapper 接口/語句級別的 SQL 日誌輸出,實現開發調試與生產監控的靈活切換。
MyBatis 按以下優先級自動綁定日誌實現 (org.apache.ibatis.logging.LogFactory):
建議:統一使用 **SLF4J + Logback/Log4j2**,避免多框架衝突。
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-slf4j2-impl</artifactId> <!-- SLF4J 綁定 Log4j2 -->
<version>2.23.1</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.23.1</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.23.1</version>
</dependency>
<Configuration status="WARN" monitorInterval="60">
<Properties>
<Property name="sqlPattern">[%d{HH:mm:ss.SSS}] [%t] %-5level %c{1.} - %msg%n</Property>
</Properties>
<Appenders>
<Console name="Console" target="SYSTEM_OUT">
<PatternLayout pattern="${sqlPattern}"/>
</Console>
<RollingFile name="SqlFile" fileName="logs/sql.log" filePattern="logs/sql-%d{yyyy-MM-dd}.log.gz">
<PatternLayout pattern="${sqlPattern}"/>
<Policies>
<TimeBasedTriggeringPolicy interval="1"/>
<SizeBasedTriggeringPolicy size="50 MB"/>
</Policies>
<DefaultRolloverStrategy max="30"/>
</RollingFile>
</Appenders>
<Loggers>
<!-- 1. Mapper 接口級別:輸出該接口所有語句 SQL + 參數 + 結果 -->
<Logger name="com.myapp.mapper.UserMapper" level="DEBUG" additivity="false">
<AppenderRef ref="SqlFile"/>
</Logger>
<!-- 2. 單條語句級別:僅輸出 selectUserById 的 SQL -->
<Logger name="com.myapp.mapper.UserMapper.selectUserById" level="DEBUG" additivity="false">
<AppenderRef ref="SqlFile"/>
</Logger>
<!-- 3. 包級別:整個 mapper 包 -->
<Logger name="com.myapp.mapper" level="DEBUG" additivity="false">
<AppenderRef ref="SqlFile"/>
</Logger>
<!-- 4. 只輸出 SQL 不輸出參數/結果 (TRACE 級別才有參數/結果) -->
<Logger name="com.myapp.mapper" level="DEBUG" additivity="false"> <!-- DEBUG=SQL, TRACE=參數/結果 -->
<AppenderRef ref="SqlFile"/>
</Logger>
<Root level="INFO">
<AppenderRef ref="Console"/>
</Root>
</Loggers>
</Configuration>
<configuration>
<appender name="SQL_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>logs/sql.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>logs/sql-%d{yyyy-MM-dd}.log.gz</fileNamePattern>
<maxHistory>30</maxHistory>
</rollingPolicy>
<encoder>
<pattern>[%d{HH:mm:ss.SSS}] [%thread] %-5level %logger{10} - %msg%n</pattern>
</encoder>
</appender>
<!-- Mapper 接口 -->
<logger name="com.myapp.mapper.UserMapper" level="DEBUG" additivity="false">
<appender-ref ref="SQL_FILE"/>
</logger>
<!-- 單條語句 -->
<logger name="com.myapp.mapper.UserMapper.selectUserById" level="DEBUG" additivity="false">
<appender-ref ref="SQL_FILE"/>
</logger>
<root level="INFO">
<appender-ref ref="CONSOLE"/>
</root>
</configuration>
| 映射方式 | Logger 名稱 (namespace + id) | 範例 |
|---|---|---|
| 註解映射 | Mapper 接口全限定名 + 方法名 | com.myapp.mapper.UserMapper.selectById |
| XML 映射 | <mapper namespace="..."></mapper> 中的 namespace + <select id="..."> | XML: namespace="com.myapp.mapper.UserMapper" + id="selectById" → 同 com.myapp.mapper.UserMapper.selectById |
結論:無論註解還是 XML,**Logger 名稱完全一致**,配置無差別。
| MyBatis 級別 | Log4j2/Logback 級別 | 輸出內容 |
|---|---|---|
| ERROR | ERROR | 錯誤 SQL、異常堆疊 |
| WARN | WARN | 慢查詢警告等 |
| INFO | INFO | 啟動信息、緩存命中等 |
| DEBUG | DEBUG | SQL 語句、參數值、影響行數 |
| TRACE | TRACE | DEBUG 內容 + 結果集詳情、返回值 |
生產環境建議:Mapper 設置 DEBUG 只看 SQL;問題排查時臨時改 TRACE 看參數結果 (熱重載生效)。
logging:
level:
com.myapp.mapper: DEBUG # 包級別開啟 SQL 日誌
# com.myapp.mapper.UserMapper.selectById: DEBUG # 單條語句
pattern:
console: "[%d{HH:mm:ss.SSS}] [%thread] %-5level %logger{15} - %msg%n"
file:
name: logs/application.log
logback:
rollingpolicy:
max-history: 30
settings.logImpl=STDOUT_LOGGING 或無依賴自動回退。logPrefix 自定義前綴區分多租戶/數據源。TRACE 級別序列化結果集極慢,**嚴禁生產常開**。DEBUG 即可輸出 SQL 與參數,TRACE 額外輸出結果集。additivity="false" 避免重複輸出。