《深入理解Mybatis原理》MyBatis初始化机制详解

主要构件及其相互关系

主要构件:

主要的核心部件解释如下:

  • SqlSession: 作为MyBatis工作的主要顶层API,表示和数据库交互的会话,完成必要数据库增删改查功能
  • Executor:MyBatis执行器,是MyBatis 调度的核心,负责SQL语句的生成和查询缓存的维护
  • StatementHandler: 封装了JDBC Statement操作,负责对JDBC statement 的操作,如设置参数、将Statement结果集转换成List集合。
  • ParameterHandler: 负责对用户传递的参数转换成JDBC Statement 所需要的参数,
  • ResultSetHandler:负责将JDBC返回的ResultSet结果集对象转换成List类型的集合;
  • TypeHandler: 负责java数据类型和jdbc数据类型之间的映射和转换
  • MappedStatement: MappedStatement维护了一条节点的封装,
  • SqlSource: 负责根据用户传递的parameterObject,动态地生成SQL语句,将信息封装到BoundSql对象中,并返回
  • BoundSql: 表示动态生成的SQL语句以及相应的参数信息
  • Configuration: MyBatis所有的配置信息都维持在Configuration对象之中。

MyBatis初始化的方式

MyBatis的初始化可以有两种方式:

  • 基于XML配置文件:基于XML配置文件的方式是将MyBatis的所有配置信息放在XML文件中,MyBatis通过加载XML配置文件,将配置文信息组装成内部的Configuration对象。
  • 基于Java API:这种方式不使用XML配置文件,需要MyBatis使用者在Java代码中,手动创建Configuration对象,然后将配置参数set 进入Configuration对象中。

基于XML配置

现在就从使用MyBatis的简单例子入手,深入分析一下MyBatis是怎样完成初始化的,都初始化了什么。看以下代码:

// mybatis初始化
String resource = "mybatis-config.xml";  
InputStream inputStream = Resources.getResourceAsStream(resource);  
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);// 创建SqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();  // 执行SQL语句
List list = sqlSession.selectList("com.foo.bean.BlogMapper.queryAllBlogInfo");

上述语句的作用是执行com.foo.bean.BlogMapper.queryAllBlogInfo 定义的SQL语句,返回一个List结果集。总的来说,上述代码经历了三个阶段:

  • mybatis初始化
  • 创建SqlSession
  • 执行SQL语句

上述代码的功能是根据配置文件mybatis-config.xml 配置文件,创建SqlSessionFactory对象,然后产生SqlSession,执行SQL语句。而mybatis的初始化就发生在第三句:SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

那么第三句到底发生了什么。

MyBatis初始化基本过程

SqlSessionFactoryBuilder根据传入的数据流生成Configuration对象,然后根据Configuration对象创建默认的SqlSessionFactory实例。

初始化的基本过程如下序列图所示:

由上图所示,mybatis初始化要经过简单的以下几步:

  1. 调用SqlSessionFactoryBuilder对象的build(inputStream)方法;
  2. SqlSessionFactoryBuilder会根据输入流inputStream等信息创建XMLConfigBuilder对象;
  3. SqlSessionFactoryBuilder调用XMLConfigBuilder对象的parse()方法;
  4. XMLConfigBuilder对象返回Configuration对象;
  5. SqlSessionFactoryBuilder根据Configuration对象创建一个DefaultSessionFactory对象;
  6. SqlSessionFactoryBuilder返回 DefaultSessionFactory对象给Client,供Client使用。

SqlSessionFactoryBuilder相关的代码如下所示:

public SqlSessionFactory build(InputStream inputStream)  {  return build(inputStream, null, null);  
}  public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties)  {  try  {  //2. 创建XMLConfigBuilder对象用来解析XML配置文件,生成Configuration对象  XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);  //3. 将XML配置文件内的信息解析成Java对象Configuration对象  Configuration config = parser.parse();  //4. 根据Configuration对象创建出SqlSessionFactory对象  return build(config);  } catch (Exception e) {  throw ExceptionFactory.wrapException("Error building SqlSession.", e);  } finally {  ErrorContext.instance().reset();  try {  inputStream.close();  } catch (IOException e) {  // Intentionally ignore. Prefer previous error.  }  }
}// 从此处可以看出,MyBatis内部通过Configuration对象来创建SqlSessionFactory,用户也可以自己通过API构造好Configuration对象,调用此方法创SqlSessionFactory  
public SqlSessionFactory build(Configuration config) {  return new DefaultSqlSessionFactory(config);  
}  

上述的初始化过程中,涉及到了以下几个对象:

  • SqlSessionFactoryBuilder : SqlSessionFactory的构造器,用于创建SqlSessionFactory,采用了Builder设计模式
  • Configuration :该对象是mybatis-config.xml文件中所有mybatis配置信息
  • SqlSessionFactory:SqlSession工厂类,以工厂形式创建SqlSession对象,采用了Factory工厂设计模式
  • XmlConfigParser :负责将mybatis-config.xml配置文件解析成Configuration对象,共SqlSessonFactoryBuilder使用,创建SqlSessionFactory

创建Configuration对象的过程

接着上述的 MyBatis初始化基本过程讨论,当SqlSessionFactoryBuilder执行build()方法,调用了XMLConfigBuilder的parse()方法,然后返回了Configuration对象。那么parse()方法是如何处理XML文件,生成Configuration对象的呢?

  • XMLConfigBuilder会将XML配置文件的信息转换为Document对象

而XML配置定义文件DTD转换成XMLMapperEntityResolver对象,然后将二者封装到XpathParser对象中,XpathParser的作用是提供根据Xpath表达式获取基本的DOM节点Node信息的操作。如下图所示:

  • 之后XMLConfigBuilder调用parse()方法

会从XPathParser中取出<configuration>节点对应的Node对象,然后解析此Node节点的子Node:properties, settings, typeAliases,typeHandlers, objectFactory, objectWrapperFactory, plugins, environments,databaseIdProvider, mappers:

public Configuration parse() {  if (parsed) {  throw new BuilderException("Each XMLConfigBuilder can only be used once.");  }  parsed = true;  //源码中没有这一句,只有 parseConfiguration(parser.evalNode("/configuration"));  //为了让读者看得更明晰,源码拆分为以下两句  XNode configurationNode = parser.evalNode("/configuration");  parseConfiguration(configurationNode);  return configuration;  
}  
/** * 解析 "/configuration"节点下的子节点信息,然后将解析的结果设置到Configuration对象中 */  
private void parseConfiguration(XNode root) {  try {  //1.首先处理properties 节点     propertiesElement(root.evalNode("properties")); //issue #117 read properties first  //2.处理typeAliases  typeAliasesElement(root.evalNode("typeAliases"));  //3.处理插件  pluginElement(root.evalNode("plugins"));  //4.处理objectFactory  objectFactoryElement(root.evalNode("objectFactory"));  //5.objectWrapperFactory  objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));  //6.settings  settingsElement(root.evalNode("settings"));  //7.处理environments  environmentsElement(root.evalNode("environments")); // read it after objectFactory and objectWrapperFactory issue #631  //8.database  databaseIdProviderElement(root.evalNode("databaseIdProvider"));  //9.typeHandlers  typeHandlerElement(root.evalNode("typeHandlers"));  //10.mappers  mapperElement(root.evalNode("mappers"));  } catch (Exception e) {  throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + e, e);  }  
} 

注意:在上述代码中,还有一个非常重要的地方,就是解析XML配置文件子节点<mappers>的方法mapperElements(root.evalNode("mappers")), 它将解析我们配置的Mapper.xml配置文件,Mapper配置文件可以说是MyBatis的核心,MyBatis的特性和理念都体现在此Mapper的配置和设计上。

  • 然后将这些值解析出来设置到Configuration对象中

解析子节点的过程这里就不一一介绍了,用户可以参照MyBatis源码仔细揣摩,我们就看上述的environmentsElement(root.evalNode("environments")); 方法是如何将environments的信息解析出来,设置到Configuration对象中的:

/** * 解析environments节点,并将结果设置到Configuration对象中 * 注意:创建envronment时,如果SqlSessionFactoryBuilder指定了特定的环境(即数据源); *      则返回指定环境(数据源)的Environment对象,否则返回默认的Environment对象; *      这种方式实现了MyBatis可以连接多数据源 */  
private void environmentsElement(XNode context) throws Exception {  if (context != null)  {  if (environment == null)  {  environment = context.getStringAttribute("default");  }  for (XNode child : context.getChildren())  {  String id = child.getStringAttribute("id");  if (isSpecifiedEnvironment(id))  {  //1.创建事务工厂 TransactionFactory  TransactionFactory txFactory = transactionManagerElement(child.evalNode("transactionManager"));  DataSourceFactory dsFactory = dataSourceElement(child.evalNode("dataSource"));  //2.创建数据源DataSource  DataSource dataSource = dsFactory.getDataSource();  //3. 构造Environment对象  Environment.Builder environmentBuilder = new Environment.Builder(id)  .transactionFactory(txFactory)  .dataSource(dataSource);  //4. 将创建的Envronment对象设置到configuration 对象中  configuration.setEnvironment(environmentBuilder.build());  }  }  }  
}private boolean isSpecifiedEnvironment(String id)  
{  if (environment == null)  {  throw new BuilderException("No environment specified.");  }  else if (id == null)  {  throw new BuilderException("Environment requires an id attribute.");  }  else if (environment.equals(id))  {  return true;  }  return false;  
} 
  • 返回Configuration对象

将上述的MyBatis初始化基本过程的序列图细化:

基于Java API

当然可以使用XMLConfigBuilder手动解析XML配置文件来创建Configuration对象,代码如下:

String resource = "mybatis-config.xml";  
InputStream inputStream = Resources.getResourceAsStream(resource);  
// 手动创建XMLConfigBuilder,并解析创建Configuration对象  
XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, null,null); // 看这里 
Configuration configuration = parser.parse();  
// 使用Configuration对象创建SqlSessionFactory  
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(configuration);  
// 使用MyBatis  
SqlSession sqlSession = sqlSessionFactory.openSession();  
List list = sqlSession.selectList("com.foo.bean.BlogMapper.queryAllBlogInfo");  

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/861732.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Docker安装与配置

由于格式和图片解析问题,为了更好的阅读体验,可以前往 阅读原文为什么出现Docker?传统的开发和部署存在着许多环境和配置的不兼容的问题,docker就是将环境和代码统一打包的来解决这些兼容问题。Docker是一个统一了运行环境和配置问题的虚拟容器技术,是一个内核级虚拟技术。…

读数据保护:工作负载的可恢复性22DR运行手册

DR运行手册1. 购买DR软件 1.1. 自行选购DR软件,意味着你可以把它安装到你自己所管理的服务器上1.1.1. 服务器可能是实体机1.1.2. 能是你所拥有的(或你向云平台购买的)虚拟机1.2. 必须全面负责它们的安保工作1.2.1. 任何一个安保疏失,都是你的责任1.2.2. 必须确保硬件、操作…

使用canvas把图片变成圆角

在前端开发中,你可以使用HTML的<canvas>元素来将图片变成圆角。以下是一个简单的步骤指南:准备HTML结构:<!DOCTYPE html> <html lang="en"> <head><meta charset="UTF-8"><meta name="viewport" content=&q…

OpenCL设备端并行执行内核

OpenCL设备端并行执行内核 Vortex存储库的tests/OpenCL目录中有OpenCL测试程序。OpenCL程序分为主机代码[cc|cpp]和设备代码kernel.cl。 OpenCL通过在设备端并行执行内核来加快速度。在tests/opencl/sgemm中的代码作为一个具体的例子。代码经过了轻微修改,使差异更加清晰。 1)…

两本新书《智能汽车传感器:原理设计应用》《AI芯片开发核心技术详解》推荐

两本书推荐《AI芯片开发核心技术详解》、《智能汽车传感器:原理设计应用》由清华大学出版社资深编辑赵佳霓老师策划编辑的新书《AI芯片开发核心技术详解》已经出版,京东、淘宝天猫、当当等网上,相应陆陆续续可以购买。该书强力解析AI芯片的核心技术开发,内容翔实、知识点新…

字符串编码(ASCII, GBK, ANSI, Unicode(‘u‘), UTF-8编码)(转载)

GBK编码 GBK编码专门用来解决中文编码的,是双字节的。不论中英文都是双字节的。 由于ASCII编码不支持中文,因此,当中国人用到计算机时,就需要寻求一种编码方式来支持中文。于是,国人就定义了一套编码规则【版权声明】本篇文章以征得博主同意,再行转载。 出自【hxxjxw】 原…

致我最爱的你

IFC数据解析与渲染,施工进度自动生成与施工方案导出##############################QQ 3087438119

12.26 MapReduce初级编程实践3

(三)对给定的表格进行信息挖掘 下面给出一个child-parent的表格,要求挖掘其中的父子辈关系,给出祖孙辈关系的表格。 输入文件内容如下:child parent Steven Lucy Steven Jack Jone Lucy Jone Jack Lucy Mary Lucy …

12.27 熟悉Hive的基本操作

1.实验目的 (1)理解Hive作为数据仓库在Hadoop体系结构中的角色。 (2)熟练使用常用的HiveQL。 2.实验平台 操作系统:Ubuntu18.04(或Ubuntu16.04)。 Hadoop版本:3.1.3。 Hive版本:3.1.2。 JDK版本:1.8。 3.数据集 由《Hive编程指南》(OReilly系列,人民邮电出版社)提供…

12.23 NoSQL和关系数据库的操作比较

1.实验目的 (1)理解四种数据库(MySQL、HBase、Redis和MongoDB)的概念以及不同点; (2)熟练使用四种数据库操作常用的Shell命令; (3)熟悉四种数据库操作常用的Java API。 2.实验平台 (1)操作系统:Linux(建议Ubuntu16.04或Ubuntu18.04); (2)Hadoop版本:3.1.3; (…

12.24 MapReduce初级编程实践1

1.实验目的 (1)通过实验掌握基本的MapReduce编程方法; (2)掌握用MapReduce解决一些常见的数据处理问题,包括数据去重、数据排序和数据挖掘等。 2.实验平台 (1)操作系统:Linux(建议Ubuntu16.04或Ubuntu18.04) (2)Hadoop版本:3.1.3 3.实验步骤 (一)编程实现文件合…