Mybatis入门源码二:sql执行

后面开始分析sql执行的源码流程
也就是这一部分
Mybatis入门源码二:sql执行_第1张图片

一、factory.openSession()

image.png
Mybatis入门源码二:sql执行_第2张图片
重点关注configuration.newExecutor这个方法,获取事务处理器比较简单,就是获取一个jdbc的事务管理器。
Mybatis入门源码二:sql执行_第3张图片

  1. 这个方法通过传入的执行器类型来创建不同的执行器,有simple、batch、reuse等
  2. 如果支持缓存的话,会创建CachingExecutor执行器

执行完成之后最后生成了一个DefaultSqlSession,有关DefaultSqlSession,特别要注意一点,它是一个非线程安全的类。
Mybatis入门源码二:sql执行_第4张图片

二、获取mapper接口

image.png
Mybatis入门源码二:sql执行_第5张图片
Mybatis入门源码二:sql执行_第6张图片
Mybatis入门源码二:sql执行_第7张图片
关于knownMappers前面讲过:是一个map,里面存放的是mapper的类型和MapperProxyFactory类。
Mybatis入门源码二:sql执行_第8张图片

后面就是调用mapperProxyFactory.newInstance(sqlSession)进行mapper接口的实例化。
Mybatis入门源码二:sql执行_第9张图片
最终会拿着mapper接口、代理方法缓存 生成InvokeHandler(用来生成Jdk代理必须要的类,当调用被代理的方法的时候,会调用到InvokeHandler的invokde方法)
最终返回的代理对象就是下图所示:
image.png

三、处理查询操作

image.png
当我们调用这个查询方法的时候,最终会调用到userProxy的invoke方法
Mybatis入门源码二:sql执行_第10张图片
先看cachedInvoker方法,
Mybatis入门源码二:sql执行_第11张图片
最终会生成一个PlainMethodInvoker,这个类是MapperProxy的静态内部类
Mybatis入门源码二:sql执行_第12张图片
这里会调用到mapperMethod.execute方法, MapperMethod中,command存放的是sql的一些信息,method存放方法的一些信息
Mybatis入门源码二:sql执行_第13张图片

public class MapperMethod {

  // todo 存放sql的一些信息,其中name属性存放的是“包名、类名、方法名”
  private final SqlCommand command;
  // todo 方法的签名,主要存放方法的一些信息
  private final MethodSignature method;

  public MapperMethod(Class<?> mapperInterface, Method method, Configuration config) {
    this.command = new SqlCommand(config, mapperInterface, method);
    this.method = new MethodSignature(config, mapperInterface, method);
  }

  public Object execute(SqlSession sqlSession, Object[] args) {
    Object result;
    switch (command.getType()) {
      case INSERT: {
        Object param = method.convertArgsToSqlCommandParam(args);
        result = rowCountResult(sqlSession.insert(command.getName(), param));
        break;
      }
      case UPDATE: {
        Object param = method.convertArgsToSqlCommandParam(args);
        result = rowCountResult(sqlSession.update(command.getName(), param));
        break;
      }
      case DELETE: {
        Object param = method.convertArgsToSqlCommandParam(args);
        result = rowCountResult(sqlSession.delete(command.getName(), param));
        break;
      }
      case SELECT:
        // todo 处理查询操作
        if (method.returnsVoid() && method.hasResultHandler()) {
          executeWithResultHandler(sqlSession, args);
          result = null;
        } else if (method.returnsMany()) {
          // todo 返回多行记录
          result = executeForMany(sqlSession, args);
        } else if (method.returnsMap()) {
          result = executeForMap(sqlSession, args);
        } else if (method.returnsCursor()) {
          result = executeForCursor(sqlSession, args);
        } else {
          Object param = method.convertArgsToSqlCommandParam(args);
          result = sqlSession.selectOne(command.getName(), param);
          if (method.returnsOptional()
              && (result == null || !method.getReturnType().equals(result.getClass()))) {
            result = Optional.ofNullable(result);
          }
        }
        break;
      case FLUSH:
        result = sqlSession.flushStatements();
        break;
      default:
        throw new BindingException("Unknown execution method for: " + command.getName());
    }
    if (result == null && method.getReturnType().isPrimitive() && !method.returnsVoid()) {
      throw new BindingException("Mapper method '" + command.getName()
          + " attempted to return null from a method with a primitive return type (" + method.getReturnType() + ").");
    }
    return result;
  }

在execute方法里面,会处理 sql 的 INSERT(mapper.xml 中的 insert 标签)、UPDATE(mapper.xml 中的 update 标签)、DELETE(mapper.xml 中的 delete 标签)、SELECT(mapper.xml 中的 select 标签)、FLUSH(针对 BatchExecutor 执行器,执行缓存的 Statement)等操作,这里我们仅关注 select 操作
Mybatis入门源码二:sql执行_第14张图片
Mybatis入门源码二:sql执行_第15张图片
接下来调用DefaultSqlSession.selectList方法来执行
Mybatis入门源码二:sql执行_第16张图片
这里会从configuration里面通过接口对应的MappedStatement,通过执行器调用执行,由于我们默认设置了一级缓存,所以会执行到CacheingExecutor.query方法
Mybatis入门源码二:sql执行_第17张图片
Mybatis入门源码二:sql执行_第18张图片
这个delegate.query最终调用的是SimpleExecutor.query方法
Mybatis入门源码二:sql执行_第19张图片
Mybatis入门源码二:sql执行_第20张图片
最终会执行到simpleExecutor.doQuery方法
Mybatis入门源码二:sql执行_第21张图片

四、总结

本文主要介绍了 mybatis 执行 sql 的流程,介绍的内容如下:

  1. mybatis 的 sql 执行操作方法在 SqlSession 中,SqlSession 是 mybatis 的执行入口
  2. XxxMapper 是一个接口,mybatis 基于 jdk 动态代理机制会生成一个代理对象,其 InvocationHandler(具体类为 MapperProxy)的 invoker(…) 方法会获取 mapper.xml 定义的 sql 并执行
  3. 执行 XxxMapper 方法时,实际调用的是 MapperProxy#invoker(…) 方法,整个方法的执行过程中,会获取 mapper.xml 中的 sql 语句,然后使用执行器(SimpleExecutor、ReuseExecutor、BatchExecutor 等)处理 sql 的执行
  4. mybatis 提供的 DefaultSqlSession 是非线程安全的,想要线程安全,可以使用 SqlSessionManager

你可能感兴趣的:(#,Mybatis,mybatis,sql,java)