Mybatis拦截器实现限制查询条数
Mybatis拦截器实现限制查询条数问题:查询结果过大的sql导致服务慢,系统不稳定?解决思路:拦截sql,对sql进行修改,添加limit条件,限制查询结果的条数。实现:1、使用Mybatis拦截器。将拦截器类交给spring管理,使用配置文件、配置类、或直接使用@Component注解均可。目的都是将拦截器类注入spring容器中。1.1 配置文件:<?xml version="1.0"
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 {
@Bean
TableLimitInterceptor 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);
// 拦截器拦截后对象后,执行自己的业务逻辑
@Override
public 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的sql
if(null == limit && !tableName.contains("dict") ){
SQLLimit sqlLimit = new SQLLimit();
sqlLimit.setRowCount(1000);
sqlSelectQuery.setLimit(sqlLimit);
String newSql = sqlSelectQuery.toString();
// 修改 sql
ReflectUtil.setFieldValue(boundSql, "sql", newSql);
}
}
return invocation.proceed(); //程序继续运行
}
//判断是否拦截这个类型对象(根据@Intercepts注解决定),然后决定是返回一个代理对象还是返回原对象。
//每经过一个拦截器对象都会调用插件的plugin方法,也就是说,该方法会调用4次。根据@Intercepts注解来决定是否进行拦截处理。
@Override
public Object plugin(Object target) {
if (target instanceof StatementHandler) {
return Plugin.wrap(target, this);
}
}
// 可给拦截器设置一些变量对象
@Override
public 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三个值共同来确定需要拦截的具体方法)
拦截类型 | 拦截方法 |
---|---|
Executor | update, query, flushStatements, commit, rollback,getTransaction, close, isClosed |
ParameterHandler | getParameterObject, setParameters |
StatementHandler | prepare, parameterize, batch, update, query |
ResultSetHandler | handleResultSets, handleOutputParameters |
总结:拦截器可拦截上述的任意一个或多个方法, 拦截到方法后,在方法中拿到对应的参数,可根据自己的业务逻辑对参数进行修改,实现自己的业务,非常的灵活。可同时使用多个拦截器,拦截多个不同的方法不会产生冲突,并且多个拦截器可同时拦截同一个方法,此时多个拦截器会依次执行,这里就要考虑拦拦截器执行的先后顺序了。
更多推荐
所有评论(0)