Mybatis拦截器实现限制查询条数

news/2024/12/23 4:34:39/

Mybatis拦截器实现限制查询条数

问题:查询结果过大的sql导致服务慢,系统不稳定?

解决思路:拦截sql,对sql进行修改,添加limit条件,限制查询结果的条数。

实现:

1、使用Mybatis拦截器。

将拦截器类交给spring管理,使用配置文件、配置类、或直接使用@Component注解均可。

目的都是将拦截器类注入spring容器中。

任选一种配置方式

1.1 配置文件:

<?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.qxy.mybatis.interceptor.TableLimitInterceptor"/></plugins></configuration>

1.2 配置类:

@Configuration
public class MyBatisConfiguration {@BeanTableLimitInterceptor tableLimitInterceptor(){return new TableLimitInterceptor();}
}

1.3 @Component注解:(直接在拦截器类上添加注解)

2、Mybatis拦截器实现代码

实现org.apache.ibatis.plugin.Interceptor接口,重写以下方法:

public interface Interceptor {// 拦截器拦截后对象后,执行自己的业务逻辑Object intercept(Invocation invocation) throws Throwable;// 判断是否拦截这个类型对象(根据@Intercepts注解决定),然后决定是返回一个代理对象还是返回原对象。Object plugin(Object target);// 可给拦截器设置一些变量对象void setProperties(Properties properties);}
@Component
@Intercepts({@Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class, Integer.class})
})
public class TableLimitInterceptor implements Interceptor {private static final Logger log = LoggerFactory.getLogger(ChannelBusiProcessorFactory.class);// 拦截器拦截后对象后,执行自己的业务逻辑@Overridepublic Object intercept(Invocation invocation) throws Throwable {// 入参invocation指拦截到的对象StatementHandler handler = (StatementHandler) invocation.getTarget();BoundSql boundSql = handler.getBoundSql();String sql = boundSql.getSql();MySqlStatementParser mySqlStatementParser = new MySqlStatementParser(sql);SQLStatement statement = mySqlStatementParser.parseStatement();if (statement instanceof SQLSelectStatement) {SQLSelect selectQuery = ((SQLSelectStatement) statement).getSelect();MySqlSelectQueryBlock sqlSelectQuery = (MySqlSelectQueryBlock) selectQuery.getQuery();String tableName = sqlSelectQuery.getFrom().toString();SQLLimit limit = sqlSelectQuery.getLimit();// 不拦截 带有limit 并且 表名中含有 dict的sqlif(null == limit && !tableName.contains("dict") ){SQLLimit sqlLimit = new SQLLimit();sqlLimit.setRowCount(1000);sqlSelectQuery.setLimit(sqlLimit);String newSql = sqlSelectQuery.toString();// 修改 sqlReflectUtil.setFieldValue(boundSql, "sql", newSql);}}return invocation.proceed(); //程序继续运行}//判断是否拦截这个类型对象(根据@Intercepts注解决定),然后决定是返回一个代理对象还是返回原对象。//每经过一个拦截器对象都会调用插件的plugin方法,也就是说,该方法会调用4次。根据@Intercepts注解来决定是否进行拦截处理。@Overridepublic Object plugin(Object target) {if (target instanceof StatementHandler) {return Plugin.wrap(target, this);}}// 可给拦截器设置一些变量对象@Overridepublic void setProperties(Properties properties) {}
}

3、拦截器知识:

3.1 MyBatis四大核心对象(四个可以被拦截的对象):

ParameterHandler: 处理sql 参数对象

ResultsetHandler: 处理sql 返回结果集

StatementHandler: 数据库的处理对象,执行sql语句

Executor: MyBatis执行器, 用于执行增删改查操作

3.2

@Intercepts({@Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class, Integer.class})
})

@Intercepts
Intercepts注解需要一个Signature(拦截点)参数数组。通过Signature来指定拦截哪个对象里面的哪个方法。

@Intercepts:标识该类是一个拦截器;
@Signature:指明自定义拦截器需要拦截哪一个类型,哪一个方法;

type:上述四种对象类型中的一种;

method:对应接口中的哪类方法(因为可能存在重载方法);

args:对应哪一个方法的入参;

(注:type、method、args三个值共同来确定需要拦截的具体方法)

拦截类型拦截方法
Executorupdate, query, flushStatements, commit, rollback,getTransaction, close, isClosed
ParameterHandlergetParameterObject, setParameters
StatementHandlerprepare, parameterize, batch, update, query
ResultSetHandlerhandleResultSets, handleOutputParameters

总结:拦截器可拦截上述的任意一个或多个方法, 拦截到方法后,在方法中拿到对应的参数,可根据自己的业务逻辑对参数进行修改,实现自己的业务,非常的灵活。可同时使用多个拦截器,拦截多个不同的方法不会产生冲突,并且多个拦截器可同时拦截同一个方法,此时多个拦截器会依次执行,这里就要考虑拦拦截器执行的先后顺序了。


http://www.ppmy.cn/news/667454.html

相关文章

MyBatis 插件之拦截器(Interceptor),拦截查询语句

一.背景 在很多业务场景下我们需要去拦截sql&#xff0c;达到不入侵原有代码业务处理一些东西&#xff0c;比如&#xff1a;分页操作&#xff0c;数据权限过滤操作&#xff0c;SQL执行时间性能监控等等&#xff0c;这里我们就可以用到Mybatis的拦截器Interceptor 二.Mybatis核…

vue请求接口报错500,进行拦截提示服务器错误

写一个拦截器。先创建一个utils文件&#xff0c;在文件夹内新建js文件写入以下代码&#xff08;直接复制即可&#xff09; import Axios from "axios"; import router from "../router/index"; // 请求拦截器 Axios.interceptors.request.use(config >…

ADGuard 开源广告拦截器 —— 筑梦之路

主页&#xff1a;https://github.com/AdguardTeam/AdGuardHome/wiki/Getting-Started#installation发行版&#xff1a;https://github.com/AdguardTeam/AdGuardHome/releaseswget https://github.com/AdguardTeam/AdGuardHome/releases/download/v0.107.5/AdGuardHome_linux_am…

【需求实现】Tensorflow2的曲线拟合(三):Embedding层

文章目录 导读Embedding的维度问题Embedding的输入输出比较容易踩的坑input_shape与input_length的对应关系built属性 导读 这是填曲线拟合第一篇的坑&#xff0c;有关Embedding层的问题。 Embedding的维度问题 首先是上次我们提到的Embedding层&#xff0c;他确实能够做到将…

Linux--移动文件或给文件改名指令:mv

mv是move的简写 作用&#xff1a; 可以用来移动文件或者将文件改名&#xff08;move (rename) files&#xff09;&#xff0c;是Linux系统下常用的命 令&#xff0c;经常用来备份文件或者目录 语法&#xff1a; mv [选项] 源文件或目录 目标文件或目录1.mv 源文件 目标目录 作…

IBM X3650 M4服务器内存故障更换处理

故障现象&#xff1a;服务器告警灯亮起&#xff0c;显示面板有MEM和CPU亮起 如下图所示 处理方法&#xff1a; 首先确定是哪一个内存损坏&#xff0c;可以接显示屏post诊断&#xff0c;看系统刷出来的信息&#xff0c;或者也可以接上IMM口&#xff0c;登录IMM管理接口&…

IBM X3650 M4 配置 raid

此次使用IBM X3650 M4服务器配置raid阵列&#xff0c;硬件配置为5块sas和1块ssd。其中2块sas配置成raid1用作系统盘&#xff0c;其余3块sas和1块ssd统一配成raid0。dell服务器配置raid步骤会持续补充上 一、进入WebBIOS界面 启动服务器等待出现如上界面后按照提示按CtrlH键进入…

Echarts 自定义工具栏事件 || 柱状图和饼状图之间的切换

echarts中有柱状图和折线图之间的切换,却没有柱状图和饼图直接的切换不过echarts有自定义工具栏方法,我们可以通过自定工具栏的方法来实现echarts没有的图形切换toolbox 中的 feature 自定方法 (title: 鼠标放上去显示的文字;icon: 自定工具栏的图标的path路径;onclick: 点击事…