利用Mybatis怎么对配置文件进行解析
创始人
2024-12-26 12:02:18
0次

Mybatis是如何解析xml的

构建Configuration

利用Mybatis怎么对配置文件进行解析

我们调用new SqlSessionFactoryBuilder().build()方法的最终目的就是构建 Configuration对象,那么Configuration何许人也?Configuration对象是一个配置管家, Configuration对象之中维护着所有的配置信息。
Configuration的代码片段如下

public class Configuration {
 //环境
 protected Environment environment;
 protected boolean safeRowBoundsEnabled;
 protected boolean safeResultHandlerEnabled = true;
 protected boolean mapUnderscoreToCamelCase;
 protected boolean aggressiveLazyLoading;
 protected boolean multipleResultSetsEnabled = true;
 protected boolean useGeneratedKeys;
 protected boolean useColumnLabel = true;
 protected boolean cacheEnabled = true;
 protected boolean callSettersOnNulls;
 protected boolean useActualParamName = true;
 protected boolean returnInstanceForEmptyRow;
 
 //日志信息的前缀
 protected String logPrefix;
 
 //日志接口
 protected Class logImpl;
 
 //文件系统接口
 protected Class vfsImpl;
 
 //本地Session范围
 protected LocalCacheScope localCacheScope = LocalCacheScope.SESSION;
 
 //数据库类型
 protected JdbcType jdbcTypeForNull = JdbcType.OTHER;
 
 //延迟加载的方法
 protected Set lazyLoadTriggerMethods = new HashSet(
   Arrays.asList(new String[] { "equals", "clone", "hashCode", "toString" }));
 
 //默认执行语句超时
 protected Integer defaultStatementTimeout;
 
 //默认的执行器
 protected ExecutorType defaultExecutorType = ExecutorType.SIMPLE;
 
 //数据库ID
 protected String databaseId;
 
 //mapper注册表
 protected final MapperRegistry mapperRegistry = new MapperRegistry(this);
 
 //拦截器链
 protected final InterceptorChain interceptorChain = new InterceptorChain();
 
 //类型处理器
 protected final TypeHandlerRegistry typeHandlerRegistry = new TypeHandlerRegistry();
 
 //类型别名
 protected final TypeAliasRegistry typeAliasRegistry = new TypeAliasRegistry();
 
 //语言驱动
 protected final LanguageDriverRegistry languageRegistry = new LanguageDriverRegistry();

 //mapper_id 和 mapper文件的映射
 protected final Map mappedStatements = new StrictMap(
   "Mapped Statements collection");
   
 //mapper_id和缓存的映射
 protected final Map caches = new StrictMap("Caches collection");
 
 //mapper_id和返回值的映射
 protected final Map resultMaps = new StrictMap("Result Maps collection");
 
 //mapper_id和参数的映射
 protected final Map parameterMaps = new StrictMap("Parameter Maps collection");
 
 //资源列表
 protected final Set loadedResources = new HashSet();
 
 未完.......
}

构建MappedStatement

在Configuration中,有个mappedStatements的属性,这是个MappedStatement对象Map的集合,其key是这个mapper的namespace+对应节点的id,而value是一个MappedStatement对象。
在构建Configuration的时候,会去解析我们的配置文件。
解析配置文件的关键代码如下

private void parseConfiguration(XNode root) {
 try {
 //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"));
 } catch (Exception e) {
 throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + e, e);
 }
}

上诉代码段倒数第三行mapperElement(root.evalNode("mappers"));就是解析mappers处就是把我们的mapper文件封装成MappedStatement对象,然后保存到Configuration的mappedStatements属性中,其中key是这个mapper的namespace+对应节点的id,而value是一个MappedStatement对象。保存的地方关键代码如下

configuration.addMappedStatement(statement);

addMappedStatement()方法代码如下

protected final Map mappedStatements = new StrictMap(
   "Mapped Statements collection");

public void addMappedStatement(MappedStatement ms) {
mappedStatements.put(ms.getId(), ms);
}

那么这个MappedStatement的又是何许人也?我们可以简单的把MapperStatement理解为对sql的一个封装,在MappedStatement中保存着一个SqlSource对象,其中就存有SQL的信息。相关代码如下

public final class MappedStatement {
	private SqlSource sqlSource;
}

SqlSource 代码如下

public interface SqlSource {
 BoundSql getBoundSql(Object parameterObject);
}

BoundSql代码如下

public class BoundSql {
 private final String sql;
 private final List parameterMappings;
}

关于二级缓存
我们在Configuration中看到了一个caches属性

protected final Map caches = new StrictMap<>("Caches collection");

这个东西的作用是什么呢?其实是关于Mybatis的二级缓存的。在解析配置文件的过程中,如果用到了二级缓存,便会把这个ID和对象也保存到configuration的caches中,相关代码如下

public void addCache(Cache cache) {
 caches.put(cache.getId(), cache);
}

构建SqlSessionFactory

在Configuration对象构建完毕之后,就该依赖Configuration对象去构建SqlSessionFactory对象了,相关代码如下

public SqlSessionFactory build(Configuration config) {
 return new DefaultSqlSessionFactory(config);
}

我们暂且把SqlSessionFactory称为SqlSession工厂吧,SqlSessionFactory中有两个方法,openSession()和getConfiguration()
SqlSessionFactory代码如下

public interface SqlSessionFactory {
 SqlSession openSession();
 //其余openSession重载方法略…
 Configuration getConfiguration();
}

构建SqlSession

openSession()方法会返回一个SqlSession对象,SqlSession又是何许人也?SqlSession可以理解为程序与数据库打交道的一个工具,通过它,程序可以往数据库发送SQL执行。
SqlSession代码如下

public interface SqlSession extends Closeable {
  T selectOne(String statement);
  T selectOne(String statement, Object parameter);
  List selectList(String statement);
  List selectList(String statement, Object parameter);
 //其余增删查改方法略…
}

相关内容

热门资讯

空调连续工作多久需要停机休息 空调连续工作的时间取决于多个因素,包括空调的型号、功率、使用环境和维护情况等。一般来说,空调可以连续...
空调哪个符号是除湿的 空调除湿功能通常用一个水滴形状的符号表示。不同品牌和型号的空调遥控器可能会有所差异,但一般来说,除湿...
格力空调多长时间加一次氟利昂 1、一般情况下,空调对氟利昂的使用量是非常小的,所以在空调使用了四年左右的时候再考虑加也没问题。2、...
空调用多长时间需要加氟一次 一般情况下是五年。当出现以下这几种情况时,空调才需要加氟。1、空调的室内机和室外机各有两个接口,当接...
格调生活·C标思享荟:卡萨帝在... 9月12日的郑州龙湖金融岛,夜风轻拂,灯光璀璨。“C标时刻共传奇——卡萨帝思享荟暨20周年品牌盛典郑...
品牌价值破千亿、高端份额持续领... 9月12日,“C标时刻共传奇——卡萨帝思享荟暨20周年品牌盛典郑州站”在郑州龙湖金融岛举办。2026...
空调主板坏了修800还是换新的 空调主板坏了是修还是换新,需要考虑多个因素,以下是一些建议:1. 维修成本:如果维修费用较低,比如 ...
空调开多久需要休息多长时间 问题:空调开多久需要休息多长时间回答:1、在使用空调的过程中,一般空调开7~8个小时左右需要休息2~...
中央空调多长时间清洗一次 1、一般空调开机前清洗一次即可,空调开机中间时段再清洗一次,空调关机时清洗一次,这样比较合理。2、空...
中央空调氟利昂多久加一次 看空调制热和制冷程度,很多人的观点认为氟利昂必须一年放一次,其实这个观点是错误的,理解上面有点偏差,...