Custom Mybatis interceptor development

1. Demand analysis

Requirements: obtain the SQL executed by Mybatis at the code level, modify the SQL, and execute the modified SQL

Scheme: Mybatis Interceptor:

 

 

Note: after adding an interceptor, all methods will be intercepted

Thinking: in fact, interceptors are equivalent to Spring's AOP programming

Fine grained: in the Mybatis framework, sql is finally handed over to the Sqlsession for execution. What the interceptor intercepts is actually:

  • 1. Executor execution phase
  • 2. ParameterHandler parameter processing phase
  • 3. StatementHandler precompile processing phase
  • 4. ResultSetHandler result set processing phase
Note: we are implementing Sql Before, you need to get Mybatis of SqlSession Object, but frame SqlSession There are four other objects below,
therefore SqlSession Just a shopkeeper,
What really works is Executor And other four objects: Executor,StatementHandler,ParameterHandler,ResultSetHandler. 

More vivid drawing metaphor:

 

 

Continue analysis:

Theoretically, if you want to intercept, all methods of these four objects can intercept

But principle is principle and reality is reality

Just like the String class in Java, there are always several common methods in it

Two common objects are mainly intercepted here:

 

According to the SQL execution cycle of Mybatis, the Executor will hand over the SQL to the StatementHandler for processing,

Therefore, our common interception method is StatementHandler, and the Sql at this stage has completed precompiling, and placeholders appear, which is more comprehensive for Sql (at this time, except for the parameter not assigned, everything else is complete, waiting to be executed)

2. Familiar with interceptor development structure

1. Code

Class implements the interceptor interface @ Override

// Core interception logic writing    
public Object intercept(Invocation invocation) throws Throwable { // Write interception logic
// Release the method return invocation.proceed(); } // Pass the target of this interceptor to the next interceptor @Override public Object plugin(Object target) { // When the target class is StatementHandler Type, the target class is wrapped. Otherwise, the target class is returned directly,Reduce the number of times the target is represented if (target instanceof StatementHandler) { System.out.println("Wrapper: : "); return Plugin.wrap(target, this); } else { System.out.println("pass on Wrapper: : "); return target; } @Override public void setProperties(Properties properties) { //The of the configuration file can be received here property Parameters are like local variables in workflow. If you need to define parameters in business, you can use this method // System.out.println(properties.getProperty("name")); }

 

Class label interception methods and parameters (to prevent method overloading, the uniqueness of parameter discrimination method is required)

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

}

 

2. Configure

In mybatis config Configure interceptors through plugins tag in XML #

Or use SpringBoot to quickly define the @ Configure tag to identify beans

Thinking: how to control the execution sequence of interceptors?
         For example, I want the interceptor x After execution, execute the interceptor y
 Reference link:https://juejin.cn/post/6926849748481605646

OK, here we go. The sql corresponding to the interface executed to each mapper file will work. (including the Count query automatically generated by PageHelper, which will also be intercepted)

Thinking: 1,How to intercept only SELECT Type sql,Automatic filtering update Type?
     2,How to intercept the specified mapper Interface method?
         
Scheme:1,Can be intercepted invocation Parameter use reflection to obtain this execution sql of 
        MappedStatement,Then obtain sqlCommandType
         
     2,Available in mapper Adding custom annotations at the interface method level is also through reflection 
        Obtain the annotation flag bit to determine whether it should be intercepted or not, and pass meaningful information through the annotation 
        value

 

 

3. More detailed analysis

Why intercept the prepare of StatementHandler

The Executor will be handed over to the StatementHandler (for lower level analysis, why use prepare)

  

When MyBatis works, the StatementHandler interface object used is actually the RoutingStatementHandler object. The meaning of routing is always access.

We can understand it as polymorphism:

StatementHandler statmentHandler = new RountingStatementHandler();

According to the source code, you can see the order of the call structure

 

 

Why? because

1. The query update needs to be prepre (see the source code)
2. Obtain the Connection (see the source code parameters)
Equivalent to JDBC} doing whatever you want

 

 

4. Under what circumstances will interceptors be used

When you need to operate sql: paging, optimistic locking (set version number verification, report errors directly if verification fails, and update the version directly if verification succeeds)

5. Example: handling general paging

Pseudo code

Interceptor coming in

Obtain pageIndex through the current thread (non thread needs to be used as a parameter, and it is more decoupled in a thread.) multiple links in a thread need the same variable, and remember to clear it with ThreadLocal.)

 

 

Connection executes cout query to obtain the starting page number of limit

Modify sql execution

6. Analyze the implementation principle of pageindex

1. How to generate_ How to execute the count method object

2. How to support the validation of only the first query statement under the current start

  

7. In depth development part II: optimistic lock

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

1

 

 

 

 

 

 

 

 

 

 

2

 

 

 

 

 

3

 

 

 

 

 

 

 

 

 

 

 

9

 

 

 

 

 

 

 

3

 

 

 

 

 

 

 

2

 

Added by anelka9 on Thu, 13 Jan 2022 08:28:25 +0200