当前位置: 首页 > news >正文

MyBatis 日志与调试技巧:让 SQL 执行过程完全透明

🔍 MyBatis 日志与调试技巧:让 SQL 执行过程完全透明

文章目录

  • 🔍 MyBatis 日志与调试技巧:让 SQL 执行过程完全透明
  • 🧠 一、MyBatis 日志体系概览
    • 💡 MyBatis 日志模块架构
    • 📊 日志级别与信息对应关系
  • ⚙️ 二、日志工厂配置详解
    • 💡 日志工厂配置方式
    • 🔧 各日志框架配置示例
  • 🔍 三、SQL 打印与参数还原
    • 💡 开启完整SQL日志输出
    • 🎯 日志输出效果对比
  • 📊 四、性能追踪与慢SQL监控
    • 💡 慢SQL检测配置
    • 🔧 慢SQL监控实现
    • 📈 SQL性能监控配置
  • 🛠️ 五、实战调试技巧
    • 💡 常见问题排查指南
    • 🔧 高级调试技巧
    • 📊 调试工具对比
  • 💡 六、总结与最佳实践
    • 📚 日志配置最佳实践
    • 🚀 性能与可读性平衡建议
    • 🛡️ 生产环境建议
    • 🔧 快速调试清单

🧠 一、MyBatis 日志体系概览

💡 MyBatis 日志模块架构

MyBatis Core
Log Factory
SLF4J
Log4J2
Log4J
JDK Logging
StdOut
具体实现绑定

​​MyBatis 日志核心特点​​:

  • 🔌 ​​插件化架构​​:支持多种日志框架
  • 📝 ​​分级输出​​:不同级别显示不同信息
  • 🔍 ​​参数可视化​​:支持SQL参数占位符替换
  • ⚡ ​​性能可控​​:避免日志输出影响性能

📊 日志级别与信息对应关系

日志级别输出信息适用场景
DEBUG完整SQL语句、参数、结果开发调试
TRACE最详细信息,包括缓存操作深度排查
INFO关键操作日志生产环境
WARN警告信息问题预警
ERROR错误信息错误排查

⚙️ 二、日志工厂配置详解

💡 日志工厂配置方式

MyBatis 支持多种日志实现,以下是常见配置方式:

​​1. mybatis-config.xml 配置​​:

<configuration><settings><!-- 设置日志实现 --><setting name="logImpl" value="SLF4J"/></settings>
</configuration>

​​2. Spring Boot 配置​​:

# application.yml
mybatis:configuration:log-impl: org.apache.ibatis.logging.slf4j.Slf4jImpl

​​3. 代码配置​​:

SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream);org.apache.ibatis.logging.LogFactory.useSlf4jLogging();

🔧 各日志框架配置示例

​​SLF4J + Logback 配置​​:

<!-- logback.xml -->
<configuration><!-- MyBatis SQL日志单独配置 --><logger name="com.example.mapper" level="DEBUG" additivity="false"><appender-ref ref="SQL_APPENDER"/></logger><appender name="SQL_APPENDER" class="ch.qos.logback.core.ConsoleAppender"><encoder><pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern></encoder></appender><root level="INFO"><appender-ref ref="SQL_APPENDER"/></root>
</configuration>

​​Log4J2 配置​​:

<!-- log4j2.xml -->
<Configuration><Loggers><!-- MyBatis Mapper层日志 --><Logger name="com.example.mapper" level="debug" additivity="false"><AppenderRef ref="SqlConsole"/></Logger><Root level="info"><AppenderRef ref="Console"/></Root></Loggers><Appenders><Console name="SqlConsole" target="SYSTEM_OUT"><PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/></Console></Appenders>
</Configuration>

🔍 三、SQL 打印与参数还原

💡 开启完整SQL日志输出

# application.properties
# 开启MyBatis SQL日志
logging.level.com.example.mapper=DEBUG# 显示SQL参数(Log4J2特有)
logging.level.org.apache.ibatis.transaction.jdbc.JdbcTransaction=DEBUG
logging.level.org.apache.ibatis.executor.BaseExecutor=DEBUG

🎯 日志输出效果对比

​​默认输出(参数占位符)​​:

DEBUG: ==>  Preparing: SELECT * FROM users WHERE id = ? AND status = ? 
DEBUG: ==> Parameters: 1(Integer), 1(Integer)
DEBUG: <==      Total: 1

​​参数替换后输出​​(需要额外配置):

DEBUG: Executing SQL: SELECT * FROM users WHERE id = 1 AND status = 1
DEBUG: Execution time: 45ms

🔧 配置SQL参数美化输出

// 自定义SQL日志拦截器
@Intercepts({@Signature(type = Executor.class, method = "update", args = {MappedStatement.class, Object.class}),@Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class})
})
public class SqlLogInterceptor implements Interceptor {private static final Logger logger = LoggerFactory.getLogger("SQL_LOGGER");@Overridepublic Object intercept(Invocation invocation) throws Throwable {MappedStatement ms = (MappedStatement) invocation.getArgs()[0];Object parameter = invocation.getArgs()[1];BoundSql boundSql = ms.getBoundSql(parameter);String sql = boundSql.getSql();Object parameterObject = boundSql.getParameterObject();// 美化SQL输出String formattedSql = formatSql(sql, parameterObject);long start = System.currentTimeMillis();try {return invocation.proceed();} finally {long cost = System.currentTimeMillis() - start;logger.debug("SQL: {} | Time: {}ms", formattedSql, cost);}}private String formatSql(String sql, Object parameter) {// 简单的参数替换逻辑if (parameter instanceof Map) {Map<?, ?> paramMap = (Map<?, ?>) parameter;for (Map.Entry<?, ?> entry : paramMap.entrySet()) {String key = ":" + entry.getKey();String value = entry.getValue() != null ? entry.getValue().toString() : "NULL";sql = sql.replace(key, "'" + value + "'");}}return sql.replaceAll("\\s+", " ").trim();}
}

📊 四、性能追踪与慢SQL监控

💡 慢SQL检测配置

# Spring Boot Actuator 监控配置
management:endpoints:web:exposure:include: health,metrics,prometheusendpoint:health:show-details: alwaysmetrics:distribution:percentiles:mybatis.sql.timer: 0.5,0.95,0.99# 数据源监控
spring:datasource:hikari:metrics-tracker: true

🔧 慢SQL监控实现

// 慢SQL检测拦截器
@Component
@Slf4j
public class SlowSqlInterceptor implements Interceptor {private static final long SLOW_SQL_THRESHOLD = 1000; // 1秒@Overridepublic Object intercept(Invocation invocation) throws Throwable {long startTime = System.currentTimeMillis();try {return invocation.proceed();} finally {long costTime = System.currentTimeMillis() - startTime;if (costTime > SLOW_SQL_THRESHOLD) {// 记录慢SQLlog.warn("Slow SQL detected: {}ms", costTime);// 获取SQL信息MappedStatement ms = (MappedStatement) invocation.getArgs()[0];Object parameter = invocation.getArgs()[1];BoundSql boundSql = ms.getBoundSql(parameter);log.warn("Slow SQL: {}", boundSql.getSql());log.warn("Parameters: {}", boundSql.getParameterObject());// 发送告警(可选)alertSlowSql(boundSql.getSql(), costTime);}// 记录指标Metrics.timer("sql.execution.time").record(costTime, TimeUnit.MILLISECONDS);}}private void alertSlowSql(String sql, long costTime) {// 集成告警系统,如发送邮件、短信等}
}

📈 SQL性能监控配置

// Micrometer SQL监控
@Configuration
public class MetricsConfig {@Beanpublic MeterRegistryCustomizer<MeterRegistry> metricsCustomizer() {return registry -> {// 监控SQL执行时间Timer.builder("sql.execution.time").description("SQL execution time").register(registry);// 监控SQL错误率Counter.builder("sql.error.count").description("SQL error count").register(registry);};}
}

🛠️ 五、实战调试技巧

💡 常见问题排查指南

问题现象可能原因解决方案
看不到SQL日志日志级别配置错误检查logging.level.com.example.mapper=DEBUG
参数显示为?日志框架不支持参数美化使用自定义拦截器或P6Spy
日志输出太杂乱日志范围太广精确配置Mapper包路径
性能开销大日志级别过高生产环境使用INFO级别

🔧 高级调试技巧

​​1. 使用P6Spy进行SQL监控​​:

# 使用P6Spy数据源
spring:datasource:url: jdbc:p6spy:mysql://localhost:3306/testdriver-class-name: com.p6spy.engine.spy.P6SpyDriver# p6spy.properties
modulelist=com.p6spy.engine.logging.P6LogFactory,com.p6spy.engine.outage.P6OutageFactory
logMessageFormat=com.p6spy.engine.spy.appender.CustomLineFormat
customLogMessageFormat=%(currentTime)|%(executionTime)|%(category)|%(sql)
  1. MyBatis原生参数打印​​:
<!-- 在mybatis-config.xml中开启详细日志 -->
<settings><setting name="logPrefix" value="MYBATIS_DEBUG."/>
</settings>
  1. 动态调整日志级别​​:
// 运行时动态调整日志级别
@RestController
public class LogLevelController {@PostMapping("/admin/log-level")public String changeLogLevel(@RequestParam String level) {LoggerContext loggerContext = (LoggerContext) LoggerFactory.getILoggerFactory();// 修改MyBatis Mapper的日志级别loggerContext.getLogger("com.example.mapper").setLevel(Level.valueOf(level));return "Log level changed to: " + level;}
}

📊 调试工具对比

工具优点缺点适用场景
MyBatis内置日志无需额外依赖功能有限简单调试
P6Spy功能强大,支持格式化需要更改数据源配置深度调试
自定义拦截器完全可控,定制性强需要开发工作量特定需求
APM工具全链路监控,生产级需要额外部署生产环境

💡 六、总结与最佳实践

📚 日志配置最佳实践

​​开发环境配置​​:

# application-dev.yml
logging:level:com.example.mapper: DEBUGorg.apache.ibatis: TRACEpattern:console: "%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n"

​​生产环境配置​​:

# application-prod.yml
logging:level:com.example.mapper: WARNorg.apache.ibatis: ERRORfile:path: /app/logsname: /app/logs/app.log

🚀 性能与可读性平衡建议

开发环境
测试环境
生产环境
日志配置
环境类型
详细日志
关键日志
错误日志
DEBUG级别
INFO级别
WARN级别

🛡️ 生产环境建议

  1. ​​避免过度日志​​:生产环境使用WARN级别,避免性能影响
  2. 日志分离​​:将SQL日志单独输出到文件,便于分析
  3. 监控告警​​:设置慢SQL告警阈值(如:>1秒) ​​
  4. 定期审计​​:定期分析SQL日志,优化性能瓶颈

🔧 快速调试清单

  1. ✅ 检查日志级别配置
  2. ✅ 确认Mapper包路径正确
  3. ✅ 验证日志框架依赖
  4. ✅ 测试参数显示是否正常
  5. ✅ 确认慢SQL监控生效

文章转载自:

http://mDYlgj1w.rnmmh.cn
http://Jg21UE2Y.rnmmh.cn
http://fxQ5zQEk.rnmmh.cn
http://BUyi5coh.rnmmh.cn
http://NPF4wwU2.rnmmh.cn
http://uDSoYWsD.rnmmh.cn
http://lPm0cXnO.rnmmh.cn
http://rPuDPJy1.rnmmh.cn
http://yXUVab6X.rnmmh.cn
http://vmIWzZOb.rnmmh.cn
http://pOyOYkrQ.rnmmh.cn
http://lWRZW3CZ.rnmmh.cn
http://1JwBRNBL.rnmmh.cn
http://J3yPSxJw.rnmmh.cn
http://lxTVjjJY.rnmmh.cn
http://5zfNrgiD.rnmmh.cn
http://tQz8tkfk.rnmmh.cn
http://w8j0g5EF.rnmmh.cn
http://mkujvoWU.rnmmh.cn
http://DPFJ6nWx.rnmmh.cn
http://KFjs5XzI.rnmmh.cn
http://fBgeMH18.rnmmh.cn
http://EBGhxBZp.rnmmh.cn
http://S18NZWQD.rnmmh.cn
http://IIhaq5Ed.rnmmh.cn
http://k9sD428r.rnmmh.cn
http://tyk9O5rW.rnmmh.cn
http://tCYAGKyQ.rnmmh.cn
http://Kdevi2Op.rnmmh.cn
http://kOdeBpdj.rnmmh.cn
http://www.dtcms.com/a/363654.html

相关文章:

  • Node.js 命令行交互王者:inquirer 模块实战指南
  • 你们公司的 QPS 是怎么统计出来的?这 5 种常见方法我踩过一半的坑!
  • LazyLLM教程 | 第7讲:检索升级实践:亲手打造“更聪明”的文档理解系统!
  • Text2SQL与DataAgent技术深度对比与实践指南
  • 【算法笔记 day six】二分算法的第三部分
  • Linux下Qt样式配置
  • Qt内存映射到文件,解决打开大文件占用内存高的问题
  • Qt5 多媒体大纲
  • 基础算法之二分算法 --- 1
  • 基于SpringBoot的校园资料分享平台
  • 力扣242:有效的字母异位词
  • 漏扫工具使用
  • C++的演化历史
  • Windows控制台颜色修改
  • anaconda下载与pycharm解析器配置
  • TypeScript:内置高级类型
  • vue2 跟 vue3 对比总结
  • Java集合遍历的方法有哪些
  • T40N君正/INGENIC专业嵌入式CPU计算能力,集成XBurst2双核处理器(1.2GHz)、RISC-V协处理器和神经网络加速器(2TOPS算力)
  • 在 macOS 下升级 Python 几种常见的方法
  • 【LeetCode数据结构】栈和队列的应用
  • 洛谷P3811 【模板】模意义下的乘法逆元
  • 硬件开发1-51单片机1
  • 嵌入式 - 硬件:51单片机
  • LeetCode算法日记 - Day 29: 重排链表、合并 K 个升序链表
  • HTML第三课:特殊元素
  • CICD实战(3) - 使用Arbess+GitLab+Hadess实现Java项目构建/上传制品库
  • 人工智能之数学基础:分布函数对随机变量的概率分布情况进行刻画
  • PromptHero-最受欢迎的AI提示词网站
  • TIOBE 8月编程语言榜深度解析:Python占比突破26%,Perl成最大黑马