首页 > 数据库 >sql拦截器

sql拦截器

时间:2024-08-23 21:29:17浏览次数:6  
标签:拦截器 sql ibatis boundSql org apache import

好用的sql拦截器

​ 写项目的时候遇到了好用的sql拦截器,自记录,整体结构如下:

image

import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class MybatisConfiguration {

    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor(){
        MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();
        mybatisPlusInterceptor.addInnerInterceptor(new MybatisPlusAllSqlLog());
        return mybatisPlusInterceptor;
    }

}
import com.baomidou.mybatisplus.extension.plugins.inner.InnerInterceptor;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.ParameterMapping;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;
import org.apache.ibatis.type.TypeHandlerRegistry;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.CollectionUtils;

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

public class MybatisPlusAllSqlLog implements InnerInterceptor {
    public static final Logger log = LoggerFactory.getLogger("sys-sql");

    @Override
    public void beforeQuery(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
        logInfo(boundSql, ms, parameter);
    }

    @Override
    public void beforeUpdate(Executor executor, MappedStatement ms, Object parameter) throws SQLException {
        BoundSql boundSql = ms.getBoundSql(parameter);
        logInfo(boundSql, ms, parameter);
    }

    private static void logInfo(BoundSql boundSql, MappedStatement ms, Object parameter) {
        try {
            log.info("parameter = " + parameter);
            // 获取到节点的id,即sql语句的id
            String sqlId = ms.getId();
            log.info("sqlId = " + sqlId);
            // 获取节点的配置
            Configuration configuration = ms.getConfiguration();
            // 获取到最终的sql语句
            String sql = getSql(configuration, boundSql, sqlId);
            log.info("完整的sql:{}", sql);
        } catch (Exception e) {
            log.error("异常:{}", e.getLocalizedMessage(), e);
        }
    }

    // 封装了一下sql语句,使得结果返回完整xml路径下的sql语句节点id + sql语句
    public static String getSql(Configuration configuration, BoundSql boundSql, String sqlId) {
        return sqlId + ":" + showSql(configuration, boundSql);
    }

    // 进行?的替换
    public static String showSql(Configuration configuration, BoundSql boundSql) {
        // 获取参数
        Object parameterObject = boundSql.getParameterObject();
        List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
        // sql语句中多个空格都用一个空格代替
        String sql = boundSql.getSql().replaceAll("[\\s]+", " ");
        if (!CollectionUtils.isEmpty(parameterMappings) && parameterObject != null) {
            // 获取类型处理器注册器,类型处理器的功能是进行java类型和数据库类型的转换
            TypeHandlerRegistry typeHandlerRegistry = configuration.getTypeHandlerRegistry();
            // 如果根据parameterObject.getClass()可以找到对应的类型,则替换
            if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) {
                sql = sql.replaceFirst("\\?",
                        Matcher.quoteReplacement(getParameterValue(parameterObject)));
            } else {
                // MetaObject主要是封装了originalObject对象,提供了get和set的方法用于获取和设置originalObject的属性值,主要支持对JavaBean、Collection、Map三种类型对象的操作
                MetaObject metaObject = configuration.newMetaObject(parameterObject);
                for (ParameterMapping parameterMapping : parameterMappings) {
                    String propertyName = parameterMapping.getProperty();
                    if (metaObject.hasGetter(propertyName)) {
                        Object obj = metaObject.getValue(propertyName);
                        sql = sql.replaceFirst("\\?",
                                Matcher.quoteReplacement(getParameterValue(obj)));
                    } else if (boundSql.hasAdditionalParameter(propertyName)) {
                        // 该分支是动态sql
                        Object obj = boundSql.getAdditionalParameter(propertyName);
                        sql = sql.replaceFirst("\\?",
                                Matcher.quoteReplacement(getParameterValue(obj)));
                    } else {
                        // 打印出缺失,提醒该参数缺失并防止错位
                        sql = sql.replaceFirst("\\?", "缺失");
                    }
                }
            }
        }
        return sql;
    }

    // 如果参数是String,则添加单引号, 如果是日期,则转换为时间格式器并加单引号; 对参数是null和不是null的情况作了处理
    private static String getParameterValue(Object obj) {
        String value;
        if (obj instanceof String) {
            value = "'" + obj.toString() + "'";
        } else if (obj instanceof Date) {
            DateFormat formatter = DateFormat.getDateTimeInstance(DateFormat.DEFAULT,
                    DateFormat.DEFAULT, Locale.CHINA);
            value = "'" + formatter.format(new Date()) + "'";
        } else {
            if (obj != null) {
                value = obj.toString();
            } else {
                value = "";
            }
        }
        return value;
    }

}
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 java.util.Properties;


@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, CacheKey.class, BoundSql.class})})
public class SqlStatementInterceptor implements Interceptor {

    public static final Logger log = LoggerFactory.getLogger("sys-sql");

    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        long startTime = System.currentTimeMillis();
        try {
            return invocation.proceed();
        } finally {
            long timeConsuming = System.currentTimeMillis() - startTime;
            log.info("执行SQL:{}ms", timeConsuming);
            if (timeConsuming > 999 && timeConsuming < 5000) {
                log.info("执行SQL大于1s:{}ms", timeConsuming);
            } else if (timeConsuming >= 5000 && timeConsuming < 10000) {
                log.info("执行SQL大于5s:{}ms", timeConsuming);
            } else if (timeConsuming >= 10000) {
                log.info("执行SQL大于10s:{}ms", timeConsuming);
            }
        }
    }

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

    @Override
    public void setProperties(Properties properties) {

    }
}

标签:拦截器,sql,ibatis,boundSql,org,apache,import
From: https://www.cnblogs.com/ruanchenjian/p/18377105

相关文章

  • centos 安装Postgretsql
    前言:官方的安装教程:https://www.postgresql.org/download/linux/redhat/官方教程中似乎只支持centos6和7,并且采用yum下载安装Postgretsql的版本也只有Postgretsql8和Postgretsql9的;想装所以其他版本的Postgresql,可以通过下载对应版本的压缩包文件,解压,编译安装注:Postgresql各......
  • 速通MySQL
    MySQL问题总结优化1.定位慢查询开源工具:Arthas,skywalking开启MySQL自带的慢日志:在my.cnf(Windows版是my.ini)配置一下:#开启MySQL慢日志查询开关slow_query_log=1#设置慢日志的时间为2秒,SQL语句查询时间超过2秒就会被计入慢查询中long_query_time=2配置完毕后慢SQL......
  • 使用 MySQL Shell 获取 MySQL 诊断信息(译)
    收集全面的诊断信息可能会让人望而却步。知道要运行哪些查询以获取所需数据更像是一种艺术形式,而非其他什么。幸运的是,对于那些不太擅长艺术的人来说,MySQLShell使得获取这些信息变得更加容易。让我们来看一下。设置在我们开始之前,我们需要连接到一个MySQL实例。在本演示中,我......
  • SQL Server查找哪些执行慢的语句
    1、根据https://learn.microsoft.com/zh-cn/troubleshoot/sql/database-engine/performance/troubleshoot-slow-running-queries网址提供的脚本。SELECTreq.session_id,req.total_elapsed_timeASduration_ms,req.cpu_timeAScpu_time_ms,req.total_......
  • docker对的tomcat、mysql、redis、nginx的安装
    本章篇章主要讲解了docker对常用软件的安装说明总体步骤:搜索镜像、拉取镜像、查看镜像、启动镜像、停止容器、移除容器tomcatdockerseachertomcat//也可以在dockerhub上面查找tomcat镜像dockerpulltomcat从dockerhub上拉取tomcat镜像到本地dockerimages//查看是否......
  • mysql8.x通过备份文件及binlog日志恢复数据
    问题简述记一次mysql数据库被误删(是整个库被删了)后的还原前提条件数据库版本为mysql8.x以上具有库被删除前的完整备份数据库开启binlog最近备份时间不能超过日志删除时间#查看数据库是否开启binlogshowvariableslike'log_bin';#默认binlog存储位置/var/lib/mysql......
  • docker mysql导入导出 nginx
    导出MySQL文件mysqldump--no-tablespaces-uroot-pabc>abc.sql导入MySQL文件mysql-uwpp-pvGgM701wWSBNwj8--default-character-set=utf8wpp<D:\wpp\nest\tmp\wpp.sql问题:docker中MySQL无法输入中文解决:dockerexec-itmysqlenvLANG=C.UTF-8/bin/bash将权限json......
  • MySQL日志
    MySQL日志MySQL日志类型MySQL日志有以下几种类型:错误日志:用于记录MySQL服务器启动、运行和停止时发生的错误的相关信息。二进制日志:记录了所有DDL和DML语句。查询日志:查询日志记录了客户端所有操作语句。慢查询日志:慢查询日志记录了所有执行时间超过参数long_que......
  • MySQL 持久化系统变量
    setpersist会将变量持久化到文件mysqld-auto.cnf文件中,该文件位于数据目录下。resetpersist会移除mysqld-auto.cnf文件中持久化的变量。 MySQL可以在运行时持久化全局系统变量。虽然许多系统变量可以在启动时通过my.cnf配置文件设置,或在运行时使用set语句设置,但这......
  • 重置MySQL表中自增字段的起始id
    导言在进行项目开发的时候,往往会自己编辑一些测试用例,但是这些用例会影响我们自增字段的起始id,虽然对我们项目没有多大影响,但是对于强迫症来说,不是从1顺着一个一个开始,感觉很不适应,所以特意搜了一下方法,然后记录一下处理方法mysql给我们提供了强大的函数功能,其中ALTERTABLE......