通过mybatis的拦截器对SQL进行打标

1、背景

在我们开发的过程中,一般需要编写各种SQL语句,万一生产环境出现了慢查询,那么我们如何快速定位到底是程序中的那个SQL出现的问题呢?

2、解决方案

如果我们的数据访问层使用的是mybatis的话,那么我们可以通过mybatis提供的拦截器拦截系统中的SQL,然后将 mapper的命名空间和id追加到原始SQL的末尾,当作一个注释,这样不就可以实现吗? 类似效果如下:

sql 复制代码
select * from customer where phone = 'aaaaa';/**com.huan.study.mybatis.mappers.CustomerMapper.findCustomer*/

3、核心实现步骤

1、拦截器拦截SQL进行打标

java 复制代码
package com.huan.study.mybatis.plugin;

import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.plugin.*;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.reflection.SystemMetaObject;

import java.sql.Connection;

/**
 * 在原始的Sql语句后面追加 sql id,方面知道当前查询语句是那个mapper文件中的
 *
 * @author huan
 * @date 2025/3/11 - 00:30
 */
@Slf4j
@Intercepts(
        {
                @Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class, Integer.class})
        }
)
public class PrintSqlIdInterceptor implements Interceptor {
    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        StatementHandler statementHandler = (StatementHandler) invocation.getTarget();
        MetaObject metaStatementHandler = MetaObject.forObject(statementHandler,
                SystemMetaObject.DEFAULT_OBJECT_FACTORY,
                SystemMetaObject.DEFAULT_OBJECT_WRAPPER_FACTORY,
                SystemMetaObject.NULL_META_OBJECT.getReflectorFactory());
        BoundSql boundSql = statementHandler.getBoundSql();
        MappedStatement mappedStatement = (MappedStatement) metaStatementHandler.getValue("delegate.mappedStatement");
        String id = mappedStatement.getId();
        log.info("sql语句的id : {}", id);

        String sql = boundSql.getSql();
        if (!sql.endsWith(";")) {
            sql += ";";
        }
        sql = sql + "/**" + id + "*/";

        metaStatementHandler.setValue("delegate.boundSql.sql", sql);
        return invocation.proceed();
    }

    @Override
    public Object plugin(Object target) {
        return Plugin.wrap(target, this);
    }
}

2、配置插件

mybatis-config.xml中进行插件的配置

xml 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <plugins>
        <plugin interceptor="com.huan.study.mybatis.plugin.PrintSqlIdInterceptor"/>
    </plugins>

</configuration>

4、实现效果如下

sql 复制代码
select * from customer where phone = 'aaaaa';/**com.huan.study.mybatis.mappers.CustomerMapper.findCustomer*/
insert into customer(phone,address) values ('12345','湖北');/**com.huan.study.mybatis.mappers.CustomerMapper.addCustomer*/

可以看到我们对每个SQL都进行了打标,方便SQL的追踪

5、完整代码

https://gitee.com/huan1993/spring-cloud-parent/tree/master/mybatis/mybatis-sql-marking

相关推荐
云老大TG:@yunlaoda3604 分钟前
开通华为云国际站代理商的UCS服务需要哪些资质?
大数据·数据库·华为云·云计算
总有刁民想爱朕ha8 分钟前
Windows Server 2019部署MySQL 8教程
数据库·windows·mysql
纪伊路上盛名在9 分钟前
记1次BioPython Entrez模块Elink的debug
前端·数据库·python·debug·工具开发
程序员水自流12 分钟前
MySQL数据库自带系统数据库功能介绍
java·数据库·mysql·oracle
旧梦吟16 分钟前
脚本网页 三人四字棋
前端·数据库·算法·css3·html5
小光学长20 分钟前
基于ssm的考研复习平台w0ws1848(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。
数据库
-大头.23 分钟前
数据库高可用架构终极指南
数据库·架构
Elastic 中国社区官方博客27 分钟前
Elasticsearch:构建一个 AI 驱动的电子邮件钓鱼检测
大数据·数据库·人工智能·elasticsearch·搜索引擎·ai·全文检索
德育处主任Pro33 分钟前
在亚马逊云上解决RDS、MariaDB 与 Aurora MySQL复制延迟实战指南
数据库·mysql·mariadb
l1t38 分钟前
解决PostgreSQL中找不到uniq函数的错误
数据库·postgresql