Mybatis占位符#和$的区别?源码解读

[复制链接]
发表于 2023-2-9 20:13:59 | 显示全部楼层 |阅读模式
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文件中的各个标签
  1. public class XMLMapperBuilder extends BaseBuilder {
  2.   ...
  3.   private final MapperBuilderAssistant builderAssistant;
  4.   private final Map<String, XNode> sqlFragments;
  5.   ...
  6.   
  7.     public void parse() {
  8.       if (!configuration.isResourceLoaded(resource)) {
  9.         // xml文件解析逻辑
  10.         configurationElement(parser.evalNode("/mapper"));
  11.         configuration.addLoadedResource(resource);
  12.         bindMapperForNamespace();
  13.       }
  14.       parsePendingResultMaps();
  15.       parsePendingCacheRefs();
  16.       parsePendingStatements();
  17.     }
  18.     private void configurationElement(XNode context) {
  19.       try {
  20.         // 解析xml文件内的namespace、cache-ref、cache、parameterMap、resultMap、sql、select、insert、update、delete等各种标签
  21.         String namespace = context.getStringAttribute("namespace");
  22.         if (namespace == null || namespace.isEmpty()) {
  23.           throw new BuilderException("Mapper's namespace cannot be empty");
  24.         }
  25.         builderAssistant.setCurrentNamespace(namespace);
  26.         cacheRefElement(context.evalNode("cache-ref"));
  27.         cacheElement(context.evalNode("cache"));
  28.         parameterMapElement(context.evalNodes("/mapper/parameterMap"));
  29.         resultMapElements(context.evalNodes("/mapper/resultMap"));
  30.         sqlElement(context.evalNodes("/mapper/sql"));
  31.         buildStatementFromContext(context.evalNodes("select|insert|update|delete"));
  32.       } catch (Exception e) {
  33.         throw new BuilderException("Error parsing Mapper XML. The XML location is '" + resource + "'. Cause: " + e, e);
  34.       }
  35.     }
  36. }
复制代码
最后会把 namespace、cache-ref、cache、parameterMap、resultMap、select、insert、update、delete等标签内容解析结果放到 builderAssistant 对象中,将sql标签解析结果放到sqlFragments对象中,其中 由于 builderAssistant 对象会保存select、insert、update、delete标签内容解析结果我们对 builderAssistant 对象进行深入了解
  1. public class MapperBuilderAssistant extends BaseBuilder {
  2. ...
  3. }
  4. public abstract class BaseBuilder {
  5.   protected final Configuration configuration;
  6.   ...
  7. }  
  8. public class Configuration {
  9.   ...
  10.   protected final Map<String, MappedStatement> mappedStatements = new StrictMap<MappedStatement>("Mapped Statements collection")
  11.       .conflictMessageProducer((savedValue, targetValue) ->
  12.           ". please check " + savedValue.getResource() + " and " + targetValue.getResource());
  13.   protected final Map<String, Cache> caches = new StrictMap<>("Caches collection");
  14.   protected final Map<String, ResultMap> resultMaps = new StrictMap<>("Result Maps collection");
  15.   protected final Map<String, ParameterMap> parameterMaps = new StrictMap<>("Parameter Maps collection");
  16.   protected final Map<String, KeyGenerator> keyGenerators = new StrictMap<>("Key Generators collection");
  17.   protected final Set<String> loadedResources = new HashSet<>();
  18.   protected final Map<String, XNode> sqlFragments = new StrictMap<>("XML fragments parsed from previous mappers");
  19.   ...
  20. }
复制代码
builderAssistant 对象继承至 BaseBuilder,BaseBuilder 类中包含一个 configuration 对象属性, configuration 对象中会保存xml文件标签解析结果至自身对应属性mappedStatements、caches、resultMaps、sqlFragments。
这里有个问题上面提到的sql标签结果会放到 XMLMapperBuilder 类的 sqlFragments 对象中,为什么 Configuration 类中也有个 sqlFragments 属性?

这里回看上文 buildSqlSessionFactory() 方法最后

原来 XMLMapperBuilder 类中的 sqlFragments 属性就来自Configuration类
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
继续阅读请点击广告

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

×
回复

使用道具 举报

×
登录参与点评抽奖,加入IT实名职场社区
去登录
快速回复 返回顶部 返回列表