Mybatis interceptor implementation limits the number of queries

Mybatis interceptor implementation limits the number of queries

Question: The query result is too large, resulting in slow service and unstable system?

Solution idea: intercept sql, modify sql, add limit condition, and limit the number of query results.

accomplish:

1. Use Mybatis interceptor.

Hand over the interceptor class to spring management, use configuration files, configuration classes, or directly use @Component annotations.

The purpose is to inject the interceptor class into the spring container.

choose a configuration

1.1 Configuration file:

<?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 class:

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

1.3 @Component annotation: (add annotation directly on the interceptor class)

2. Mybatis interceptor implementation code

Implement org.apache.ibatis.plugin.Interceptorthe interface, overriding the following methods:

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. Interceptor knowledge:

3.1 Four core objects of MyBatis (four objects that can be intercepted):

ParameterHandler: handle sql parameter objects

ResultsetHandler: process sql return result set

StatementHandler: The processing object of the database, execute the sql statement

Executor: MyBatis executor, used to perform addition, deletion, modification and query operations

3.2

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

The @Intercepts
Intercepts annotation requires an array of Signature (intercept point) parameters. Use Signature to specify which method in which object to intercept.

@Intercepts : Identify the class as an interceptor;
@Signature : Indicate which type and method the custom interceptor needs to intercept;

type : one of the four object types above;

method : Which type of method in the corresponding interface (because there may be overloaded methods);

args : the input parameter corresponding to which method;

(Note: The three values ​​of type, method, and args are used together to determine the specific method that needs to be intercepted)

interception type Intercept method
Executor update, query, flushStatements, commit, rollback,getTransaction, close, isClosed
ParameterHandler getParameterObject, setParameters
StatementHandler prepare, parameterize, batch, update, query
ResultSetHandler handleResultSets, handleOutputParameters

Summary: The interceptor can intercept any one or more of the above methods. After intercepting the method, get the corresponding parameters in the method, and modify the parameters according to your own business logic to realize your own business, which is very flexible. Multiple interceptors can be used at the same time. Intercepting multiple different methods will not cause conflicts, and multiple interceptors can intercept the same method at the same time. At this time, multiple interceptors will be executed sequentially. Here we must consider the execution of interceptors It's in order.

Guess you like

Origin blog.csdn.net/weixin_40307206/article/details/112724559