Mybatis執行SQL的完整過程及四大組件介紹


一切的執行從MapperProxy開始,MapperProxy是MapperProxyFactory使用SqlSession創建出來的。所以MapperProxy中包含SqlSession。

  可以看到MapperProxy調用invoke方法,進而調用MapperMethod的execute(),這些MapperMethod就是和你要執行的命令相關,比如執行select語句,則會通過SqlSession的select()方法,最終調用到Executor的query方法。Executor會再協調另外三個核心組件。

  • MapperProxyFactory用來創建MapperProxy,這個factory其實主要就是完成了InvokeHandler的bindTarget的功能。而MapperProxy只需要完成invoke方法的功能。
  • MapperProxy包含SqlSession
  • SqlSesion包含四大組件Executor,StatementHandler,ParameterHandler,ResultHandler。還包含Configuration
  • Configuration可以創建四大組件,同時Configuration還包含InterceptorChain,通過調用interceptorChain的pluginAll()方法,完成針對四大組件的插件的動態代理鏈的創建。

MapperProxy:

  • 因為Mapper接口不能直接被實例化,Mybatis利用JDK動態代理,創建MapperProxy間接實例化Mapper對象。
  • MapperProxy還可以緩存MapperMethod對象

MapperMethod:

  • 負責解析Mapper接口的方法,並封裝成MapperMethod對象
  • 將Sql命令的執行路由到恰當的SqlSesison方法上
 1 public class MapperMethod {
 2  
 3   // 保存了Sql命令的類型和鍵id
 4   private final SqlCommand command;
 5   // 保存了Mapper接口方法的解析信息
 6   private final MethodSignature method;
 7  
 8   public MapperMethod(Class<?> mapperInterface, Method method, Configuration config) {
 9     this.command = new SqlCommand(config, mapperInterface, method);
10     this.method = new MethodSignature(config, method);
11   }
12  
13   // 根據解析結果,路由到恰當的SqlSession方法上
14   public Object execute(SqlSession sqlSession, Object[] args) {
15     Object result;
16     if (SqlCommandType.INSERT == command.getType()) {
17       Object param = method.convertArgsToSqlCommandParam(args);
18       result = rowCountResult(sqlSession.insert(command.getName(), param));
19     } else if (SqlCommandType.UPDATE == command.getType()) {
20       Object param = method.convertArgsToSqlCommandParam(args);
21       result = rowCountResult(sqlSession.update(command.getName(), param));
22     } else if (SqlCommandType.DELETE == command.getType()) {
23       Object param = method.convertArgsToSqlCommandParam(args);
24       result = rowCountResult(sqlSession.delete(command.getName(), param));
25     } else if (SqlCommandType.SELECT == command.getType()) {
26       if (method.returnsVoid() && method.hasResultHandler()) {
27         executeWithResultHandler(sqlSession, args);
28         result = null;
29       } else if (method.returnsMany()) {
30         result = executeForMany(sqlSession, args);
31       } else if (method.returnsMap()) {
32         result = executeForMap(sqlSession, args);
33       } else {
34         Object param = method.convertArgsToSqlCommandParam(args);
35         result = sqlSession.selectOne(command.getName(), param);
36       }
37     } else if (SqlCommandType.FLUSH == command.getType()) {
38         result = sqlSession.flushStatements();
39     } else {
40       throw new BindingException("Unknown execution method for: " + command.getName());
41     }
42     if (result == null && method.getReturnType().isPrimitive() && !method.returnsVoid()) {
43       throw new BindingException("Mapper method '" + command.getName() 
44           + " attempted to return null from a method with a primitive return type (" + method.getReturnType() + ").");
45     }
46     return result;
47   }
48   // ...

插件的構建:

  談原理首先要知道StatementHandler,ParameterHandler,Result Handler都是代理,他們是Configuration創建,在創建過程中會調用interceptorChain.pluginAll()方法,為四大組件組裝插件(再底層是通過Plugin.wrap(target,XX, new Plugin( interceptor))來來創建的)。

插件鏈是何時構建的:

  在執行SqlSession的query或者update方法時,SqlSession會通過Configuration創建Executor代理,在創建過程中就調用interceptor的pluginAll方法組裝插件。然后executor在調用doQuery()方法的時候,也會調用Configuration的newStatementHandler方法創建StatemenHandler(和上面描述的一樣,這個handler就是個代理,也是通過interceptorChain的pluginAll方法構建插件)

插件如何執行:

  以statementhandler的prepare方法的插件為例,正如前面所說,statementhandler是一個proxy,執行他的prepare方法,將調用invokeHandler的invoke方法,而invokeHandler就是Plugin.wrap(target, xxx, new Plugin(interceptor))中的第三個參數,所以很自然invokeHanlder的invoke的方法最終就會調用interceptor對象的intercept方法。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM