前言

        因项目个别请求频率极高,需要自定义细粒度控制接口不打印执行sql,不影响别的接口打印执行sql,这里记录下实现。
 

步骤一

关闭项目本身sql日志打印

#关闭mybatis-plus日志打印
mybatis-plus:
#  configuration:
#    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl # SQL 打印
#项目使用了分表分库插件shardingsphere 需要关闭日志
shardingsphere:
  mode:
    type: Standalone  # 显式指定模式
  props:
    sql-show: false #sql日志
#项目使用logging日志打印设置
logging:
  level:
    root: info

步骤二


import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;


@Configuration
public class MybatisPlusConfig {
    @Autowired
    private MybatisPluginProperties mybatisPluginProperties;
    /**
     * 添加分页插件
     */
/*
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL)); // 如果配置多个插件, 切记分页最后添加
       // interceptor.addInnerInterceptor(new MybatisPlusAllSqlLog());

        // 这里添加 SQL 性能分析插件,用来打印 SQL 和执行时间
        // 如果有多数据源可以不配具体类型, 否则都建议配上具体的 DbType
        return interceptor;
    }
*/

    /**
     * 自定义细粒度控制sql打印
     * @return
     */
    @Bean
    public MybatisSqlLogInterceptor mybatisSqlLogInterceptor() {
        MybatisSqlLogInterceptor interceptor = new MybatisSqlLogInterceptor();
        interceptor.setSlownessThreshold(mybatisPluginProperties.getSqlLog().getSlownessThreshold());
        return interceptor;
    }
}

 MybatisUtils类


import lombok.experimental.UtilityClass;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.ParameterMapping;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.type.TypeHandlerRegistry;

import java.text.DateFormat;
import java.util.Date;
import java.util.List;
import java.util.Locale;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

@UtilityClass
public class MybatisUtils {

    private static final Pattern PARAMETER_PATTERN = Pattern.compile("\\?");

    public String getSql(MappedStatement mappedStatement, Invocation invocation) {
        Object parameter = null;
        if (invocation.getArgs().length > 1) {
            parameter = invocation.getArgs()[1];
        }
        BoundSql boundSql = mappedStatement.getBoundSql(parameter);
        Configuration configuration = mappedStatement.getConfiguration();
        return resolveSql(configuration, boundSql);
    }

    private static String resolveSql(Configuration configuration, BoundSql boundSql) {
        Object parameterObject = boundSql.getParameterObject();
        List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
        String sql = boundSql.getSql().replaceAll("[\\s]+", " ");
        if (!parameterMappings.isEmpty() && parameterObject != null) {
            TypeHandlerRegistry typeHandlerRegistry = configuration.getTypeHandlerRegistry();
            if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) {
                sql = sql.replaceFirst("\\?", Matcher.quoteReplacement(resolveParameterValue(parameterObject)));

            } else {
                MetaObject metaObject = configuration.newMetaObject(parameterObject);
                Matcher matcher = PARAMETER_PATTERN.matcher(sql);
                StringBuffer sqlBuffer = new StringBuffer();
                for (ParameterMapping parameterMapping : parameterMappings) {
                    String propertyName = parameterMapping.getProperty();
                    Object obj = null;
                    if (metaObject.hasGetter(propertyName)) {
                        obj = metaObject.getValue(propertyName);
                    } else if (boundSql.hasAdditionalParameter(propertyName)) {
                        obj = boundSql.getAdditionalParameter(propertyName);
                    }
                    if (matcher.find()) {
                        matcher.appendReplacement(sqlBuffer, Matcher.quoteReplacement(resolveParameterValue(obj)));
                    }
                }
                matcher.appendTail(sqlBuffer);
                sql = sqlBuffer.toString();
            }
        }
        return sql;
    }

    private static String resolveParameterValue(Object obj) {
        if (obj instanceof CharSequence) {
            return "'" + obj + "'";
        }
        if (obj instanceof Date) {
            DateFormat formatter = DateFormat.getDateTimeInstance(DateFormat.DEFAULT, DateFormat.DEFAULT, Locale.CHINA);
            return "'" + formatter.format(obj) + "'";
        }
        return obj == null ? "" : String.valueOf(obj);
    }
}

MybatisSqlLogInterceptor 类 

说明:MyBatis 中,Interceptor 是一个非常重要的接口,它用于在 MyBatis 执行 SQL 操作时对 SQL 执行的过程进行拦截。通过实现 Interceptor 接口,开发者可以在 MyBatis 执行 SQL 的不同阶段(如执行前、执行后、处理结果等)插入自定义的逻辑

执行sql拦截器会拦截根据自定义是否打印sql


import com.baomidou.mybatisplus.core.toolkit.SystemClock;
import com.macro.mall.common.util.RequestUtil;
import org.apache.ibatis.cache.CacheKey;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.plugin.*;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.time.Duration;

@Intercepts({
        @Signature(method = "query", type = Executor.class, args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class}),
        @Signature(method = "query", type = Executor.class, args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class, CacheKey.class, BoundSql.class}),
        @Signature(method = "update", type = Executor.class, args = {MappedStatement.class, Object.class})
})
public class MybatisSqlLogInterceptor implements Interceptor {

    private static final Logger log = LoggerFactory.getLogger("MybatisSqlLog");

    private Duration slownessThreshold = Duration.ofMillis(1000);

    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        //获取 HttpServletRequest 路径判断是否打印 或 过滤器 判断接口是否打印状态放入 如下代码
/*
        //1.获取设置是否打印请求日志
        public static Boolean getReqLogStatus(HttpServletRequest request) {
            Boolean flag = true;
            Object attribute = request.getSession().getAttribute(CommonDataConstant.REQ_LOG_STATUS);
            if(attribute!=null){
                flag = false;
            }
            return  flag;
        }


        //2.设置是否打印请求日志
        httpServletRequest.getSession().setAttribute(CommonDataConstant.REQ_LOG_STATUS, true);
*/

             
/*     
        //3.控制是否打印sql
     try{
           RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
           if(requestAttributes!=null){
               HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
               if(!RequestUtil.getReqLogStatus(request)){
                   Object results = invocation.proceed();
                   return results;
               }
           }
       }catch (Exception e){
           e.printStackTrace();
           log.error(e.getMessage());
       }*/

        MappedStatement mappedStatement = (MappedStatement) invocation.getArgs()[0];
        String mapperId = mappedStatement.getId();


        String originalSql = MybatisUtils.getSql(mappedStatement, invocation);

        long start = SystemClock.now();
        Object result = invocation.proceed();
        long duration = SystemClock.now() - start;
        // 当 SQL 执行超过我们设置的阈值,转为 WARN 级别
        if (Duration.ofMillis(duration).compareTo(slownessThreshold) < 0) {
            log.info("{} execute sql: {} ({} ms)", mapperId, originalSql, duration);
        } else {
            log.info("{} execute sql took more than {} ms: {} ({} ms)", mapperId, slownessThreshold.toMillis(), originalSql, duration);
        }
        return result;
    }

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

    // 设置慢 SQL 阈值,单位为秒
    public void setSlownessThreshold(Duration slownessThreshold) {
        this.slownessThreshold = slownessThreshold;
    }
}

MybatisPluginProperties类 


import lombok.Data;
import org.springframework.context.annotation.Configuration;

import java.time.Duration;

@Configuration
@Data
public class MybatisPluginProperties {

    private final SqlLog sqlLog = new SqlLog();

    @Data
    public static class SqlLog {

        private boolean enabled = true;

        private Duration slownessThreshold = Duration.ofMillis(1000);
    }
}

Logo

魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。

更多推荐