MyBatis 源码解析:通过源码深入理解 SQL 的执行过程

这篇博客详细解析了MyBatis的数据处理层,包括配置文件加载、解析,SQL执行,结果集映射等核心步骤。从源码层面探讨了配置加载、configuration解析、SqlSessionFactory构建、Mapper的SQL执行过程及结果映射。文章还介绍了MyBatis中使用的设计模式,如工厂模式、动态代理和责任链模式。
摘要由CSDN通过智能技术生成

一、目录

1、前言

2、配置文件加载

3、配置文件解析

4、SQL执行

5、结果集映射

6、Mybatis中的设计模式

7、总结

二、前言

1、mybatis框架图

 

如上为mybatis的框架图,在这篇文章中通过源码来重点看下数据处理层中的参数映射,SQL解析,SQL执行,结果映射

2、配置使用

获取mapper并操作数据库代码如下:

InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");	
 SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
 SqlSession sqlSession = sqlSessionFactory.openSession();
 LiveCourseMapper mapper = sqlSession.getMapper(LiveCourseMapper.class);	
 List<LiveCourse> liveCourseList = mapper.getLiveCourseList();

三、配置文件加载

配置文件加载最终还是通过
ClassLoader.getResourceAsStream来加载文件,关键代码如下:

public static InputStream getResourceAsStream(ClassLoader loader, String resource) throws IOException {
InputStream in = classLoaderWrapper.getResourceAsStream(resource, loader);
if (in == null) {
  throw new IOException("Could not find resource " + resource);
}
return in;

}

InputStream getResourceAsStream(String resource, ClassLoader[] classLoader) {
for (ClassLoader cl : classLoader) {
  if (null != cl) {

    // try to find the resource as passed
    InputStream returnValue = cl.getResourceAsStream(resource);

    // now, some class loaders want this leading "/", so we'll add it and try again if we didn't find the resource
    if (null == returnValue) {
      returnValue = cl.getResourceAsStream("/" + resource);
    }

    if (null != returnValue) {
      return returnValue;
    }
  }
}
return null;

}

四、配置文件解析

SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); 我们以 SqlSessionFactoryBuilder为入口,看下mybatis是如何解析配置文件,并创建SqlSessionFactory的。
SqlSessionFactoryBuilder.build方法实现如下:

XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
 //解析出configuration对象,并创建SqlSessionFactory
 return build(parser.parse());

重点为解析configuration对象,然后根据configuration创建DefualtSqlSessionFactory。

1、解析configuration

private void parseConfiguration(XNode root) {
try {
  Properties settings = settingsAsPropertiess(root.evalNode("settings"));
  //issue #117 read properties first
  propertiesElement(root.evalNode("properties"));
  loadCustomVfs(settings);
  typeAliasesElement(root.evalNode("typeAliases"));
  pluginElement(root.evalNode("plugins"));
  objectFactoryElement(root.evalNode("objectFactory"));
  objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));
  reflectionFactoryElement(root.evalNode("reflectionFactory"));
  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);
}
  }

通过XPathParser解析configuration节点下的properties,settings,typeAliases,plugins,objectFactory,objectWrapperFactory,reflectionFactory,environments,databaseIdProvider,typeHandlers,mappers这些节点。解析过程大体相同,都是通过XPathParser解析相关属性、子节点,然后创建相关对象,并保存到configuration对象中。这块代码相对简单,大家阅读起来没什么难度。

(1)解析properties 解析properties,并设置到configuration对象下的variables属性,protected Properties variables = new Properties();

(2)解析settings 解析settings配置,如lazyLoadingEnabled(默认false),defaultExecutorType(默认SIMPLE),jdbcTypeForNull(默认OTHER),callSettersOnNulls(默认false)

(3)解析typeAliases 通过typeAliasRegistry来注册别名,别名通过key,value的方式来进行存储,mybatis默认会创建一些基础类型的别名,如string->String.class,int->Integer.class,map->Map.class,hashmap->HashMap.class,list->List.class。别名和class关系通过HashMap来存储,

private final Map<String, Class<?>> TYPE_ALIASES = new HashMap<String, Class<?>>();

(4)解析plugins 解析插件,然后设置Configuration的InterceptorChain。 Configuration: protected final InterceptorChain interceptorChain = new InterceptorChain();

InterceptorChain:

private final List<Interceptor> interceptors = new ArrayList<Interceptor>();
public void addInterceptor(Interceptor interceptor) {
    interceptors.add(interceptor);
}

在创建的时候构造了拦截器链,在执行的时候也会经过拦截器链,此处为典型的责任链模式

(5)解析objectFactory 可以自定义ObjectFactory,对象工厂,默认为DefaultObjectFactory

(6)解析objectWrapperFactory 默认为
DefaultObjectWrapperFactory

(7)reflectionFactory 反射工厂,在通过反射创建对象时(如结果集对象),可以通过自定义的反射工厂来创建对象。objectFactory,objectWrapperFactory,reflectionFactory这又是典型的工厂模式,将对象的创建交由相应的工厂来创建。

(8)databaseIdProvider 用来支持不同的数据库,很少在项目中用到

(9)解析typeHandlers 解析TypeHandler并通过typeHandlerRegistry注册到configuration中,通过TYPE_HANDLER_MAP保存typeHandler:

private final Map<Type, Map<JdbcType, TypeHandler<?>>> TYPE_HANDLER_MAP = new HashMap<Type, Map<JdbcType, TypeHandler<?>>>();复制代码

(10)解析mappers 读取通过url指定的配置文件,然后通过XmlMapperBuilder进行解析

2、解析mapper

解析mapper的入口为XmlMapperBuilder.parse方法,在解析的时候会解析cache-ref,cache&

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值