mybatis的xml文件解析流程,以及sql执行过程(__本文类名的缩写)

Mybatis解析

select * from user where name =? and pwd=?

  1. statement:select * from user where name = and pwd=(采用直接拼接的方式,有sql注入的风险)

  2. preparestatement:​ **~.setString(1,‘name’) ~.setString(2,‘pwd’)**​ select * from user where name =‘name’andpwd=′‘{name}’ and pwd='‘nameandpwd={pwd}’'​ (采用String拼接的方式,没有sql注入的风险)

Mybatis的执行流程图

在这里插入图片描述

mybatis的四大对象:

在这里插入图片描述

流程如下:

Exeutor发起sql执行任务

1、先调用statementHandler中的prepare()进行SQL的编译

2、然后调用statementHandler中的parameterize()设置参数

2.1、这里其实真正设置参数的是`ParameterHandler`中的`setparameters()`方法,该方法与`typeHandler`进行参数类型的转换

3、然后执行query/update方法,这里使用ResultSetHandler进行结果的组装工作

3.1、这里`ResultSetHandler`又与`typeHandler`、`ObjectFactory`配合工作共同完成结果的组装工作

每一条sql语句都会绑定对应的对象:

MappedStatement:sql的ID、缓存信息、resultType、ParameterType、resultMap等信息
(mapper.xml文件就是被解析成这个对象);
Sqlsource:是MappedStatement的一个属性,是一个接口,主要提供BoundSql;
BoudSql:是建立SQL和参数的地方,有三个主要属性,ParameterMappings、ParameterObject和sql,这个对象比较重要,我们通常使用插件(实现接口Interceptor
+注解@Intercepts+mybatiscong.xml的plugin标签配置)就是对它进行拦截;

解析config.xml、mapper.xml:

@Before
public static void initFactory() {
   
   
    try {
   
   
        SqlSession session = null;
        String resource = "configuration.xml";
        // 使用io流读取配置
        InputStream inputStream;
        inputStream = Resources.getResourceAsStream(resource);
        //这里是解析配置文件
        sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        // 得到了一个会话,有了这个会话,你就可以对数据进行增,删,改,查的操作
        session = sqlSessionFactory.openSession();
    } catch (IOException e) {
   
   
        // TODO Auto-generated catch block
        e.printStackTrace();
    }

}
=======new SqlSessionFactoryBuilder().build(inputStream);
            return build(inputStream, null, null);
                XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
                  return build(parser.parse());
                         if (parsed) {
   
   
                          throw new BuilderException("Each XMLConfigBuilder can only be used once.");
                        }
                        parsed = true;
                        parseConfiguration(parser.evalNode("/configuration"));//解析节点
                        //全局的配置文件就会被解析成一个org.apache.ibatis.session.Configuration
                        return configuration;
====parser.parse()调用========parseConfiguration(parser.evalNode("/configuration"));//解析节点
    private void parseConfiguration(XNode root) {
   
   
        try {
   
   
          //标签配置顺序:
          //properties,settings,typeAliases,typeHandlers,objectFactory,objectWrapperFactory,                              //plugins,environments,databaseIdProvider,mappers
          //issue #117 read properties first
          propertiesElement(root.evalNode("properties"));
          Properties settings = settingsAsProperties(root.evalNode("settings"));
          loadCustomVfs(settings);
          loadCustomLogImpl(settings);
          typeAliasesElement(root.evalNode("typeAliases"));
          pluginElement(root.evalNode("plugins"));
          objectFactoryElement(root.evalNode("objectFactory"));
          objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));
          reflectorFactoryElement(root.evalNode("reflectorFactory"));
          settingsElement(settings);
          // read it after objectFactory and objectWrapperFactory issue #631
          environmentsElement(root.evalNode("environments"));
          databaseIdProviderElement(root.evalNode("databaseIdProvider"));
          typeHandlerElement(root.evalNode("typeHandlers"));
          mapperElement(root.evalNode("mappers"));//解析mapper节点
        } catch (Exception e) {
   
   
          throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + e, e);
        }
      }
/**
*mapper接口的方法同时写xml配置和注解配置的话会报错
*xml配置和注解配置都会被mybatis翻译成MappedStatement对象(两个mappedStatement的id相同(就是方法名),用的缓存容器是Hashmap(继承了hashmap的一个StateMap,重写了put())所以会报错)
*<mappers>
        //如何只找到mapper文件的(mapper接口+*mapper.xml)
        <package name="mapper" />
        <!-- <mapper class="" resource="" url=""/> -->
    </mappers>
*/
=============mapperElement(root.evalNode("mappers"));//解析mapper节点
    private void mapperElement(XNode parent) throws Exception {
   
   
    if (parent != null) {
   
   
      for (XNode child : parent.getChildren()) {
   
   
          //解析mapper/package节点
        if ("package".equals(child.getName())) {
   
   
          String mapperPackage = child.getStringAttribute("name");
          configuration.addMappers(mapperPackage);//各种各样的mapper文件
        } else {
   
   
          String resource = child.getStringAttribute("resource");
          String url = child.getStringAttribute("url");
          String mapperClass = child.getStringAttribute("class");
            //解析你写的<mapper>注解的这三个属性(看源码可以看出这三个属性你只能配置一个属性)
              /**
              *resource/url是资源定位符(就是路径)
              *    mapperClass你直接指定了一个接口
              */
          if (resource != null && url == null && mapperClass == null) {
   
   
              //配置了resource
            ErrorContext.instance().resource(resource);
            InputStream inputStream = Resources.getResourceAsStream(resource);
            XMLMapperBuilder mapperParser = new XMLMapperBuilder(inputStream, configuration, resource, configuration.getSqlFragments());
            mapperParser.parse();
          } else if (resource == null && url != null && mapperClass == null) {
   
   
              //配置了url
            ErrorContext.instance().resource(url);
            InputStream inputStream = Resources.getUrlAsStream(url);//拿到mapper.xml文件的输入流
            XMLMapperBuilder mapperParser = new XMLMapperBuilder(inputStream, configuration, url, configuration.getSqlFragments());
            mapperParser.parse();//解析
          } else if (resource == null && url == null && mapperClass != null) {
   
   
              //配置了mapperClass(直接拿接口了)
            Class<?> mapperInterface = Resources.classForName(mapperClass);
            configuration.addMapper(mapperInterface);
          } else {
   
   
            throw new BuilderException("A mapper element may only specify a url, resource or class, but not more than one.");
          }
        }
      }
    }
  }
===============》configuration.addMappers(mapperPackage);//各种各样的mapper文件
  public void addMappers(String packageName, Class<?> superType) {
   
   
    ResolverUtil<Class<?>> resolverUtil = new ResolverUtil<>();
    resolverUtil.find(new ResolverUtil.IsA(superType), packageName);
    Set<Class<? extends Class<?>>> mapperSet = resolverUtil.getClasses();
    for (Class<?> mapperClass : mapperSet) {
   
   
      addMapper(mapperClass);//干活的地方
    }
  }
public <T> void addMapper(Class<T> type) {
   
   
    if (type.isInterface()) {
   
   //拿接口
      if (hasMapper(type)) {
   
   //验证你是不是有一个加载的mapper接口了
        throw new BindingException("Type " + type + " is already known to the MapperRegistry.");
      }
      boolean loadCompleted = false;
      try {
   
   
        knownMappers.put(type, new 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

five-five

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值