mybatis plus 修改sql

news2024/11/15 9:52:55

原始需求

在SQL语句前面加上一个request-id

问题描述

今天收到业务同学反馈,说接入某个SDK后,request-id本地debug发现sql已经修改了,但打印的sql中却没有request-id信息

在这里插入图片描述

在这里插入图片描述

看了下代码,发现用户的代码其实就是下方 方案一代码,取不到的原因也在代码中注释了

方案一

package com.jiankunking.mybatisplus;

import static org.apache.commons.lang3.StringUtils.isNotBlank;

import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.jiankunking.utils.JkkLogUtil;
import java.lang.reflect.Field;
import java.sql.Connection;
import java.util.Properties;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.cache.CacheKey;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.SqlCommandType;
import org.apache.ibatis.plugin.Intercepts;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.plugin.Plugin;
import org.apache.ibatis.plugin.Signature;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;

@Intercepts(
    {
        @Signature(type = StatementHandler.class, method = "prepare",
            args = {Connection.class, Integer.class}),
        @Signature(type = StatementHandler.class, method = "getBoundSql", args = {}),
        @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}),
        @Signature(type = Executor.class, method = "query",
            args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class,
                CacheKey.class, BoundSql.class}),
    }
)
@Slf4j
public class MybatisPlusRequestIdInterceptor extends MybatisPlusInterceptor {
  private Boolean enabled = true;

  @Override
  public Object intercept(Invocation invocation) throws Throwable {
    Object target = invocation.getTarget();
    Object[] args = invocation.getArgs();
    BoundSql boundSql = null;
    if (target instanceof Executor) {
      Object parameter = args[1];
      boolean isUpdate = args.length == 2;
      MappedStatement ms = (MappedStatement) args[0];
      if (!isUpdate && ms.getSqlCommandType() == SqlCommandType.SELECT) {
        RowBounds rowBounds = (RowBounds) args[2];
        if (args.length == 4) {
          boundSql = ms.getBoundSql(parameter);
        } else {
          // 几乎不可能走进这里面,除非使用Executor的代理对象调用query[args[6]]
          boundSql = (BoundSql) args[5];
        }
      }
    } else {
      StatementHandler statementHandler = (StatementHandler) target;
      boundSql = statementHandler.getBoundSql();
    }

    if (enabled && boundSql != null) {
      String sql = boundSql.getSql();
      String requestId = JkkLogUtil.getCurrentRequestId();
      StringBuilder sb = new StringBuilder("/*");
      if (isNotBlank(requestId) && isNotBlank(sql)) {
        sb.append(" Jkk-request-id:").append(requestId).append(" ");
      }

      String armsTraceId = JkkLogUtil.getTraceId();
      if (isNotBlank(armsTraceId) && isNotBlank(sql)) {
        sb.append(" trace-id:").append(armsTraceId).append(" ");
      }

      String armsRpcId = JkkLogUtil.getRpcId();
      if (isNotBlank(armsRpcId)) {
        sb.append(" rpc-id:").append(armsRpcId).append(" ");
      }
      sb.append(" */");

      sb.append(sql);
      // 通过反射修改sql语句
      Field field = boundSql.getClass().getDeclaredField("sql");
      field.setAccessible(true);
      field.set(boundSql, sb.toString());
      // 这里如果不调用 return invocation.proceed();
      // 而是执行父类intercept的话,会导致反射修改的SQL无效
      // 因为父类获取sql还是基于参数再次拼接的没有直接使用boundSql
    }

    return super.intercept(invocation);
  }

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

  @Override
  public void setProperties(Properties properties) {
    enabled = Boolean.valueOf(properties.getProperty("enabled", "true"));
  }
}

方案二

直接修改mybatisplus的Statement

package com.jiankunking.mybatisplus;

import static org.apache.commons.lang3.StringUtils.isNotBlank;

import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.jiankunking.utils.JkkLogUtil;

import java.lang.reflect.Field;
import java.sql.Connection;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;

import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.cache.CacheKey;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.mapping.*;
import org.apache.ibatis.plugin.Intercepts;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.plugin.Plugin;
import org.apache.ibatis.plugin.Signature;
import org.apache.ibatis.reflection.DefaultReflectorFactory;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.reflection.SystemMetaObject;
import org.apache.ibatis.reflection.factory.DefaultObjectFactory;
import org.apache.ibatis.reflection.wrapper.DefaultObjectWrapperFactory;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;

@Intercepts(
        {
                @Signature(type = StatementHandler.class, method = "prepare",
                        args = {Connection.class, Integer.class}),
                @Signature(type = StatementHandler.class, method = "getBoundSql", args = {}),
                @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}),
                @Signature(type = Executor.class, method = "query",
                        args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class,
                                CacheKey.class, BoundSql.class}),
        }
)
@Slf4j
public class MybatisPlusRequestIdInterceptor extends MybatisPlusInterceptor {
    private Boolean enabled = true;

    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        Object target = invocation.getTarget();
        Object[] args = invocation.getArgs();
        BoundSql boundSql = null;
        if (target instanceof Executor) {
            Object parameter = args[1];
            boolean isUpdate = args.length == 2;
            MappedStatement ms = (MappedStatement) args[0];
            if (!isUpdate && ms.getSqlCommandType() == SqlCommandType.SELECT) {
                RowBounds rowBounds = (RowBounds) args[2];
                if (args.length == 4) {
                    boundSql = ms.getBoundSql(parameter);
                } else {
                    // 几乎不可能走进这里面,除非使用Executor的代理对象调用query[args[6]]
                    boundSql = (BoundSql) args[5];
                }
            }
        } else {
            StatementHandler statementHandler = (StatementHandler) target;
            boundSql = statementHandler.getBoundSql();
        }

        if (enabled && boundSql != null) {
            String sql = boundSql.getSql();
            String requestId = JkkLogUtil.getCurrentRequestId();
            StringBuilder sb = new StringBuilder("/*");
            if (isNotBlank(requestId) && isNotBlank(sql)) {
                sb.append(" Jkk-request-id:").append(requestId).append(" ");
            }

            String armsTraceId = JkkLogUtil.getTraceId();
            if (isNotBlank(armsTraceId) && isNotBlank(sql)) {
                sb.append(" trace-id:").append(armsTraceId).append(" ");
            }

            String armsRpcId = JkkLogUtil.getRpcId();
            if (isNotBlank(armsRpcId)) {
                sb.append(" rpc-id:").append(armsRpcId).append(" ");
            }
            sb.append(" */");

            sb.append(sql);
            // 通过反射修改sql语句
            //Field field = boundSql.getClass().getDeclaredField("sql");
            //field.setAccessible(true);
            //field.set(boundSql, sb.toString());

            if (target instanceof Executor) {
                setCurrentSql(invocation, sb.toString());
            } else {
                StatementHandler statementHandler = (StatementHandler) target;
                MetaObject metaObject = SystemMetaObject.forObject(statementHandler);
                metaObject.setValue("delegate.boundSql.sql", sb.toString());
            }
        }

        return super.intercept(invocation);
    }

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

    @Override
    public void setProperties(Properties properties) {
        enabled = Boolean.valueOf(properties.getProperty("enabled", "true"));
    }

    private static final int MAPPED_STATEMENT_INDEX = 0;
    private static final int PARAM_OBJ_INDEX = 1;

    private void setCurrentSql(Invocation invocation, String sql) {
        Object[] args = invocation.getArgs();
        Object paramObj = args[PARAM_OBJ_INDEX];

        MappedStatement mappedStatement = (MappedStatement) args[MAPPED_STATEMENT_INDEX];

        BoundSql boundSql = mappedStatement.getBoundSql(paramObj);
        MappedStatement newMappedStatement = copyFromMappedStatement(
                mappedStatement, new BoundSqlSqlSource(boundSql));
        MetaObject metaObject = MetaObject.forObject(newMappedStatement,
                new DefaultObjectFactory(), new DefaultObjectWrapperFactory(),
                new DefaultReflectorFactory());
        metaObject.setValue("sqlSource.boundSql.sql", sql);
        args[MAPPED_STATEMENT_INDEX] = newMappedStatement;
    }

    private class BoundSqlSqlSource implements SqlSource {
        BoundSql boundSql;

        public BoundSqlSqlSource(BoundSql boundSql) {
            this.boundSql = boundSql;
        }

        public BoundSql getBoundSql(Object parameterObject) {
            return boundSql;
        }
    }

    @SuppressWarnings({"unchecked", "rawtypes"})
    private MappedStatement copyFromMappedStatement(MappedStatement ms,
                                                    SqlSource newSqlSource) {
        MappedStatement.Builder builder = new MappedStatement.Builder(ms.getConfiguration(), ms
                .getId(), newSqlSource, ms.getSqlCommandType());
        builder.resource(ms.getResource());
        builder.fetchSize(ms.getFetchSize());
        builder.statementType(ms.getStatementType());
        builder.keyGenerator(ms.getKeyGenerator());
        // setStatementTimeout()
        builder.timeout(ms.getTimeout());
        // setParameterMap()
        builder.parameterMap(ms.getParameterMap());
        // setStatementResultMap()
        List<ResultMap> resultMaps = new ArrayList<ResultMap>();
        String id = "-inline";
        if (ms.getResultMaps() != null) {
            id = ms.getResultMaps().get(0).getId() + "-inline";
        }
        ResultMap resultMap = new ResultMap.Builder(null, id, Long.class,
                new ArrayList()).build();
        resultMaps.add(resultMap);
        builder.resultMaps(resultMaps);
        builder.resultSetType(ms.getResultSetType());
        // setStatementCache()
        builder.cache(ms.getCache());
        builder.flushCacheRequired(ms.isFlushCacheRequired());
        builder.useCache(ms.isUseCache());
        return builder.build();
    }

    //private MappedStatement getMappedStatement(Invocation invo) {
    //    Object[] args = invo.getArgs();
    //    Object mappedStatement = args[MAPPED_STATEMENT_INDEX];
    //    return (MappedStatement) mappedStatement;
    //}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1535778.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【机器学习】机器学习实验方法与原则(评价指标全面解析)

评价指标 在 不同任务 下衡量模型的性能&#xff0c;有 不同的评价指标 &#xff0c;例如&#xff1a; • 回归任务 • 平均绝对误差&#xff08; MAE &#xff09;、均方误差&#xff08; MSE &#xff09;、均方根误差&#xff08; RMSE &#xff09;等 • 分类任务 •…

QT学习之设置QLineEdit背景透明且无边框

设置styleSheet:background&#xff1a;transparent;border-width:0;border-style:outset;

挑战迎刃而解!化工行业CRM案例揭示企业扩张成功之道!

化工行业一直面临着激烈的行业竞争&#xff0c;新时代化工企业如何面对扩张挑战&#xff0c;是许多企业管理者深思的问题&#xff0c;Zoho CRM客户管理系统为化工行业的用户提供了优秀的解决方案。一起来看看Zoho CRM的实力如何吧~ 一、客户背景 Zoho CRM的这家化工行业客户&a…

绝地求生:哪把枪的机瞄让你觉得最舒服或者最“抽象”呢?

大&#xff0c;好&#xff0c;我&#xff0c;闲游盒&#xff01; 这题我会&#xff0c;我先来&#xff01; 今天本来在训练场玩呢&#xff0c;突然想到了Famas这把枪的机瞄我真的是驾驭不来.... 我灵机一动&#xff0c;想问问大家平时如果落地没捡到镜又碰到敌人的情况下&…

【创建进程】fork函数与写时拷贝

文章目录 fork函数fork如何返回两个值&#xff08;fork的工作原理&#xff09;如何解释父子进程相互输出printf 写时拷贝 fork函数 #include <unistd.h> pid_t fork(void); 返回值&#xff1a;自进程中返回0&#xff0c;父进程返回子进程id&#xff0c;出错返回-1 fork函…

网络编程:学生管理系统

一、实现功能 1.添加学生信息 2.删除学生信息 3.修改学生信息 4.查找学生信息 二、添加 int do_add(sqlite3 *ppDb) {// 准备sql语句int add_num 0;char add_name[20] "";double add_score 0;// 提示并输入数据printf("请输入学号:");scanf("%d&q…

芯片公司SAP管理架构:科技与管理的完美融合

在当今日新月异的科技时代&#xff0c;芯片公司作为信息技术领域的核心力量&#xff0c;其运营管理的复杂性日益凸显。SAP管理架构作为一种高效的企业资源规划系统&#xff0c;为芯片公司提供了强大的管理支持。本文将为您科普芯片公司SAP管理架构的相关知识。 SAP管理架构是一…

使用倒模耳机壳UV树脂胶液制作舞台监听耳返入耳式耳机壳有哪些优点?

使用倒模耳机壳UV树脂胶液制作舞台监听耳返入耳式耳机壳有很多优点&#xff0c;具体如下&#xff1a; 高音质表现&#xff1a;通过倒模工艺制作的耳机壳能够更好地贴合耳朵&#xff0c;减少声音散射和反射&#xff0c;提高声音的清晰度和质感。这对于舞台监听来说非常重要&…

USB调试工具大全-USB中文网

USB中文网在此之前开发了很多的应用层USB设备调试工具&#xff0c;再加上收集的一些其它相关工具&#xff0c;并将这些调试工具分享给各位USB开发者爱好者&#xff0c;帮助大家更快的学习和了解USB相关的知识。 不过酒香也怕巷子深&#xff0c;今天我们就将这些调试工具的导航…

带你学会深度学习之卷积神经网络[CNN] - 5

前言 本文不讲述如泛化&#xff0c;前向后向传播&#xff0c;过拟合等基础概念。 本文图片来源于网络&#xff0c;图片所有者可以随时联系笔者删除。 本文提供代码不代表该神经网络的全部实现&#xff0c;只是为了方便展示此模型的关键结构。 CNN&#xff0c;常用于计算机视…

Leetcode 200. 岛屿数量

心路历程&#xff1a; 在没有看图论这一章之前看这道题没什么直接的思路&#xff0c;在看完图论之后&#xff0c;学着使用DFS和BFS去套用解决。第一次自己做的时候还是遇到了很多小问题。整体思路很流畅&#xff0c;但是需要处理的细节第一次没怎么处理好&#xff0c;花了很多…

如何使用Android平板公网访问本地Linux code-server

文章目录 1.ubuntu本地安装code-server2. 安装cpolar内网穿透3. 创建隧道映射本地端口4. 安卓平板测试访问5.固定域名公网地址6.结语 1.ubuntu本地安装code-server 准备一台虚拟机,Ubuntu或者centos都可以&#xff0c;这里以VMwhere ubuntu系统为例 下载code server服务,浏览器…

OR-806A固态继电器光耦

固态继电器 VL60V输出端击穿电压光耦 高隔离电压 60 至 600V 输出耐受电压 工业温度范围&#xff1a;-40 to 85℃ 高灵敏度和高速响应、 特征 输入和输出之间的高隔离电压 &#xff08;Viso&#xff1a;5000 V rms&#xff09;。 控制低电平模拟信号 高灵敏度和高速响应…

含“AI”量上涨,智能模组SC208系列助力智慧零售全场景高质发展

AI正重塑智慧零售产业&#xff0c;加速零售在采购、生产、供应链、销售、服务等方面改善运营效率和用户体验。零售行业经历了从线下到线上再到全渠道融合发展过程&#xff0c;“提质、降本、增效、高体验”是亘古不变的商业化与智能化方向。含“AI”量逐渐上涨的智慧零售正经历…

Linux:Gitlab:16.9.2 (rpm包) 部署及基础操作(1)

1.基础环境 我只准备了一台gitlab服务器&#xff0c;访问就用真机进行访问&#xff0c;接下来介绍一下详细配置 centos7 内网ip:192.168.6.7 外网ip:172.20.10.4 运行内存&#xff1a;4G CPU:4核 先去配置基础环境 关闭防火墙以及selinux 再去下载基础的运行…

差分逻辑电平 --- SSTL、HSTL、HSUL结构

SSTL/HSTL/HSUL 属于DDR存储器接口逻辑电平&#xff0c;虽然是单端&#xff0c;本质上是差分对&#xff0c;因实现机制是将信号与参考电平Vref组成差分对进行比较。 SSTL SSTL&#xff1a;Stub Series Termination Logic&#xff0c;短截线串联端接逻辑。 我们所熟知的DDR 采…

记录西门子200:PUT和GET通讯测试

GET/PUT&#xff1a;S7-200SMART之间专有通讯协议。 准备两台Smart-PLC&#xff0c;这里使用的ST60和CR40。外加一个交换机。 CR40的地址设置是&#xff1a;192.168.2.1 用来读 ST60的地址设置是&#xff1a;192.168.2.2 用来写 打开软件&#xff0c;选择CPU-CR4配…

LeetCode_Java_递归系列(题目+思路+代码)

206.反转链表 给你单链表的头节点 head &#xff0c;请你反转链表&#xff0c;并返回反转后的链表。 示例 1&#xff1a; 输入&#xff1a;head [1,2,3,4,5] 输出&#xff1a;[5,4,3,2,1]以此类推&#xff0c;直到反转结束返回头结点 class Solution {public ListNode rever…

统计-R(相关系数)与R^2(决定系数)

1.相关系数&#xff08;R&#xff09; 定义&#xff1a;考察两个事物&#xff08;在数据里我们称之为变量&#xff09;之间的相关程度。 假设有两个变量X&#xff0c;Y&#xff0c;那么两个变量间的皮尔逊相关系数可通过以下公式计算&#xff1a; 公式一&#xff1a; 其中…

创建一个electron-vite项目

前置条件&#xff1a;非常重要&#xff01;&#xff01;&#xff01; npm: npm create quick-start/electronlatest yarn: yarn create quick-start/electron 然后进入目录&#xff0c;下载包文件&#xff0c;运行项目 到以上步骤&#xff0c;你已经成功运行起来一个 electr…