| Mybatis 作为国内开发中常用到的半自动 orm 框架,相信大家都很熟悉,它提供了简单灵活的xml映射配置,方便开发人员编写简单、复杂SQL,在国内互联网公司使用众多。本文针对笔者日常开发中对 Mybatis 占位符 #{} 和 ${} 使用时机结合源码,思考总结而来
 一. 启动时,mybatis-spring 解析xml文件流程图
 
 Spring 项目启动时,mybatis-spring 自动初始化解析xml文件核心流程
 
  Mybatis 在 buildSqlSessionFactory() 会遍历所有 mapperLocations(xml文件) 调用 xmlMapperBuilder.parse()解析,源码如下
 
  在 parse() 方法中, Mybatis  通过 configurationElement(parser.evalNode("/mapper")) 方法解析xml文件中的各个标签
 最后会把 namespace、cache-ref、cache、parameterMap、resultMap、select、insert、update、delete等标签内容解析结果放到 builderAssistant 对象中,将sql标签解析结果放到sqlFragments对象中,其中 由于 builderAssistant 对象会保存select、insert、update、delete标签内容解析结果我们对 builderAssistant 对象进行深入了解复制代码public class XMLMapperBuilder extends BaseBuilder {  ...  private final MapperBuilderAssistant builderAssistant;  private final Map<String, XNode> sqlFragments;  ...      public void parse() {      if (!configuration.isResourceLoaded(resource)) {        // xml文件解析逻辑        configurationElement(parser.evalNode("/mapper"));        configuration.addLoadedResource(resource);        bindMapperForNamespace();      }      parsePendingResultMaps();      parsePendingCacheRefs();      parsePendingStatements();    }    private void configurationElement(XNode context) {      try {        // 解析xml文件内的namespace、cache-ref、cache、parameterMap、resultMap、sql、select、insert、update、delete等各种标签        String namespace = context.getStringAttribute("namespace");        if (namespace == null || namespace.isEmpty()) {          throw new BuilderException("Mapper's namespace cannot be empty");        }        builderAssistant.setCurrentNamespace(namespace);        cacheRefElement(context.evalNode("cache-ref"));        cacheElement(context.evalNode("cache"));        parameterMapElement(context.evalNodes("/mapper/parameterMap"));        resultMapElements(context.evalNodes("/mapper/resultMap"));        sqlElement(context.evalNodes("/mapper/sql"));        buildStatementFromContext(context.evalNodes("select|insert|update|delete"));      } catch (Exception e) {        throw new BuilderException("Error parsing Mapper XML. The XML location is '" + resource + "'. Cause: " + e, e);      }    }}
builderAssistant 对象继承至 BaseBuilder,BaseBuilder 类中包含一个 configuration 对象属性, configuration 对象中会保存xml文件标签解析结果至自身对应属性mappedStatements、caches、resultMaps、sqlFragments。复制代码public class MapperBuilderAssistant extends BaseBuilder {...}public abstract class BaseBuilder {  protected final Configuration configuration;  ...}  public class Configuration {  ...  protected final Map<String, MappedStatement> mappedStatements = new StrictMap<MappedStatement>("Mapped Statements collection")      .conflictMessageProducer((savedValue, targetValue) ->          ". please check " + savedValue.getResource() + " and " + targetValue.getResource());  protected final Map<String, Cache> caches = new StrictMap<>("Caches collection");  protected final Map<String, ResultMap> resultMaps = new StrictMap<>("Result Maps collection");  protected final Map<String, ParameterMap> parameterMaps = new StrictMap<>("Parameter Maps collection");  protected final Map<String, KeyGenerator> keyGenerators = new StrictMap<>("Key Generators collection");  protected final Set<String> loadedResources = new HashSet<>();  protected final Map<String, XNode> sqlFragments = new StrictMap<>("XML fragments parsed from previous mappers");  ...}
这里有个问题上面提到的sql标签结果会放到 XMLMapperBuilder 类的 sqlFragments 对象中,为什么 Configuration 类中也有个 sqlFragments 属性?
 
 这里回看上文 buildSqlSessionFactory() 方法最后
 
  原来 XMLMapperBuilder 类中的 sqlFragments 属性就来自Configuration类
 免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
 |