栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

mybatis源码,SQL是如何执行的

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

mybatis源码,SQL是如何执行的

1.这里只是讲述CRUD的执行,在CRUD之前,你服务启动的时候,mybtis会把mapper和xml中的节点SQL通过反射加载到Configuration中,这个不做描述了,后面再补;

2.我们直接开始启动工程跟着代码一点点跟,看是如何执行的;
3.我的springframework版本是5.3.7 mybatis版本3.4.6 springboot版本2.5.0 jdk1.8;
注意:当版本不同时,执行的逻辑肯定是不同的,因为spring和mybatis都会进行不断的优化升级

当我们执行一个SQL的时候,会先通过org.springframework.aop.support包中的AopUtils类,来执行处理,调用了方法invokeJoinpointUsingReflection

这里入参有三个,贴下入参
1.可以看到这里的入参target是MapperProxy类,method是你的SQL方法,args是你的请求入参

2.invokeJoinpointUsingReflection 方法里面,主要有两行代码

// 这里面就做了一件事情使用 method.setAccessible(true) 改变了访问权限
ReflectionUtils.makeAccessible(method);
// 这个里面invoke了一堆代码,主要看这里
return method.invoke(target, args);

这里可以看到invoke会进入到Java Method类中的invoke,我们主要看mybatis就不介绍java的这些方法了(有的有点复杂,我也没看懂),这里可以看到进来之后继续到底下执行invoke,这个时候是调用的DelegatingMethodAccessorImpl类中的invoke来进行的执行

可以看到DelegatingMethodAccessorImpl类中,这里的invoke是调用了MethodAccessorImpl的invoke,这里实际指向的对象是NativeMethodAccessorImpl这个类

可以看到这里最后跑到了NativeMethodAccessorImpl类中,执行的invoke0,invoke0方法是用native修饰的,说明这是调用的底层非java方法,调用的C,C++写的东西了(我也看不懂底层到底干了啥,JAVA设计的真负责,C我也木有学习过)

接下来我们终于可以看框架源码了,框架看起来还是比较简单的,没java那么复杂了,我们可以看到这里最终调用的是MapperProxy类中的invoke方法,里面入参有三个,就是上面介绍invokeJoinpointUsingReflection方法的三个入参,一摸一样

  // 代码直接贴出来吧,这里invoke里面看的不多,调用的方法里面写了一堆
  @Override
  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    try {
      // 判断方法是否为Object对象的
      if (Object.class.equals(method.getDeclaringClass())) {
        return method.invoke(this, args);
        // 这里跳到连接【https://blog.csdn.net/qq_43555164/article/details/108254738】看下原因
      } else if (isDefaultMethod(method)) {
        return invokeDefaultMethod(proxy, method, args);
      }
    } catch (Throwable t) {
      throw ExceptionUtil.unwrapThrowable(t);
    }
    // 大多数情况我们会走到这里,从缓存中得到mapperMethod,没有的话会放的缓存里
    // 具体代码下面详细讲述,这里写的还挺多的
    final MapperMethod mapperMethod = cachedMapperMethod(method);
    // 这个里面是执行的关键
    return mapperMethod.execute(sqlSession, args);
  }

  // cachedMapperMethod方法,入参是你的method
  private MapperMethod cachedMapperMethod(Method method) {
    // 这里先根据methodCache拿,看能不能拿出来,methodCache是一个Map
    // private final Map methodCache;
    MapperMethod mapperMethod = methodCache.get(method);
    // 为空就去new对象去了
    if (mapperMethod == null) {
    // 别小看这一行代码,里面写了一堆(我yue你仙人,我还以为就new了个对象,写那么复杂干啥?脑子被门挤了吗?)
      mapperMethod = new MapperMethod(mapperInterface, method, sqlSession.getConfiguration());
      // 把这俩玩意丢的map缓存起来
      methodCache.put(method, mapperMethod);
    }
    return mapperMethod;
  }




--------------------------------------------华丽的分割线--------------------------------------------
    // 这里介绍下new MapperMethod(mapperInterface, method, sqlSession.getConfiguration()); 我再yue你一次仙人,G2加油,干翻T1
    // 这里实例化的时候会给对象里面的俩属性new一下,new的底下这两个东西
    // private final SqlCommand command;
    // private final MethodSignature method;
    // 介绍下三个入参
    //   mapperInterface: 这个就是你的mapper接口
    //   method: 这个是你执行的mapper里面的哪个SQL方法
    //   config: mybatis初始化的时候,把一堆东西丢config缓存里面了
    public MapperMethod(Class mapperInterface, Method method, Configuration config) {
    // 这里new对象里面写的东西有点多,底下贴吧
    this.command = new SqlCommand(config, mapperInterface, method);
    // 这里new对象里面写的东西有点多,底下贴吧
    this.method = new MethodSignature(config, mapperInterface, method);
  }
  

可以看到这个SqlCommand对象,是在MapperMethod类里面的,还是个public类,估计那会想的能给其他地方也用

可以看到这里面写了一堆东西,接下来贴代码,看看这里面干了点啥

    public SqlCommand(Configuration configuration, Class mapperInterface, Method method) {
      // 获取method的名字的 我这里方法名字是【queryUser】
      final String methodName = method.getName();
      // 获取method是属于哪个接口的 我这里是【interface com.example.demo.Mapper.UserMapper】
      final Class declaringClass = method.getDeclaringClass();
      // 调用了私有方法,又拿了个对象,看看这里面干了点啥,底下贴代码 G2牛逼,干翻了T1,nice
      MappedStatement ms = resolveMappedStatement(mapperInterface, methodName, declaringClass,
          configuration);
      if (ms == null) {
        if (method.getAnnotation(Flush.class) != null) {
          name = null;
          type = SqlCommandType.FLUSH;
        } else {
          throw new BindingException("Invalid bound statement (not found): "
              + mapperInterface.getName() + "." + methodName);
        }
      } else {
        name = ms.getId();
        type = ms.getSqlCommandType();
        if (type == SqlCommandType.UNKNOWN) {
          throw new BindingException("Unknown execution method for: " + name);
        }
      }
    }

	// 这里源码的私有方法,入参四个,上面都讲了,这里不再讲了
	// 需要注意【mapperInterface】和【declaringClass】,虽然我感觉是一摸一样,但是应该是有区别的(我现在还没发现哪里有区别)
    private MappedStatement resolveMappedStatement(Class mapperInterface, String methodName,
        Class declaringClass, Configuration configuration) {
      // 拿到俩name组成一个ID,我的是【com.example.demo.Mapper.UserMapper.queryUser】
      String statementId = mapperInterface.getName() + "." + methodName;
      // 这里configuration参数的作用,判断了下是否有这个ID和返回对应的缓存中的对象,底下看下这个方法干了点啥
      if (configuration.hasStatement(statementId)) {
        return configuration.getMappedStatement(statementId);
      } else if (mapperInterface.equals(declaringClass)) {
        return null;
      }
      for (Class superInterface : mapperInterface.getInterfaces()) {
        if (declaringClass.isAssignableFrom(superInterface)) {
          MappedStatement ms = resolveMappedStatement(superInterface, methodName,
              declaringClass, configuration);
          if (ms != null) {
            return ms;
          }
        }
      }
      return null;
    }

         
  // 需要注意下这个俩方法在configuration类里面
  public boolean hasStatement(String statementName) {
  	// 调了内部的方法hasStatement
    return hasStatement(statementName, true);
  }

  public boolean hasStatement(String statementName, boolean validateIncompleteStatements) {
    if (validateIncompleteStatements) {
      buildAllStatements();
    }
    return mappedStatements.containsKey(statementName);
  }
// 先陪女朋友过520,后面再补
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/918695.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号