目录
  • MyBatis简单介绍
  • 启动流程分析
  • 简单总结
  • 附录
    • MyBatis内置别名转换
  • 参考


MyBatis简单介绍

MyBatis是一个持久层框架,使用简单,学习成本较低。可以执行自己手写的SQL语句,比较灵活。但是MyBatis的自动化程度不高,移植性也不高,有时从一个数据库迁移到另外一个数据库的时候需要自己修改配置。

一个Mybatis最简单的使用列子如下:

public class UserDaoTest {private SqlSessionFactory sqlSessionFactory;@Beforepublic void setUp() throws Exception{ClassPathResource resource = new ClassPathResource("mybatis-config.xml");InputStream inputStream = resource.getInputStream();sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);}@Testpublic void selectUserTest(){String id = "{0003CCCA-AEA9-4A1E-A3CC-06D884BA3906}";SqlSession sqlSession = sqlSessionFactory.openSession();CbondissuerMapper cbondissuerMapper = sqlSession.getMapper(CbondissuerMapper.class);Cbondissuer cbondissuer = cbondissuerMapper.selectByPrimaryKey(id);System.out.println(cbondissuer);sqlSession.close();}}
  • 从配置文件(通常是XML文件)得到SessionFactory;
  • 从SessionFactory得到SQLSession;
  • 通过SqlSession进行CRUD和事务的操作;
  • 执行完相关操作之后关闭Session。

启动流程分析

本博客只涉及创建SessionFactory,以及从SessionFactory获取SqlSession的流程。具体执行Sql的流程会在其他博客中分析。

ClassPathResource resource = new ClassPathResource("mybatis-config.xml");
InputStream inputStream = resource.getInputStream();
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

通过上面代码发现,创建SqlSessionFactory的代码在SqlSessionFactoryBuilder中,进去一探究竟:

//整个过程就是将配置文件解析成Configration对象,然后创建SqlSessionFactory的过程
//Configuration是SqlSessionFactory的一个内部属性
public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {try {XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);return build(parser.parse());} 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.}}}public SqlSessionFactory build(Configuration config) {return new DefaultSqlSessionFactory(config);}

下面我们看下解析配置文件过程中的一些细节。

先给出一个配置文件的列子:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configurationPUBLIC "-//mybatis.org//DTD Config 3.0//EN""http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration><!--SqlSessionFactoryBuilder中配置的配置文件的优先级最高;config.properties配置文件的优先级次之;properties标签中的配置优先级最低 --><properties resource="org/mybatis/example/config.properties"><property name="username" value="dev_user"/><property name="password" value="F2Fa3!33TYyg"/></properties><!--一些重要的全局配置--><settings><setting name="cacheEnabled" value="true"/><!--<setting name="lazyLoadingEnabled" value="true"/>--><!--<setting name="multipleResultSetsEnabled" value="true"/>--><!--<setting name="useColumnLabel" value="true"/>--><!--<setting name="useGeneratedKeys" value="false"/>--><!--<setting name="autoMappingBehavior" value="PARTIAL"/>--><!--<setting name="autoMappingUnknownColumnBehavior" value="WARNING"/>--><!--<setting name="defaultExecutorType" value="SIMPLE"/>--><!--<setting name="defaultStatementTimeout" value="25"/>--><!--<setting name="defaultFetchSize" value="100"/>--><!--<setting name="safeRowBoundsEnabled" value="false"/>--><!--<setting name="mapUnderscoreToCamelCase" value="false"/>--><!--<setting name="localCacheScope" value="STATEMENT"/>--><!--<setting name="jdbcTypeForNull" value="OTHER"/>--><!--<setting name="lazyLoadTriggerMethods" value="equals,clone,hashCode,toString"/>--><!--<setting name="logImpl" value="STDOUT_LOGGING" />--></settings><typeAliases></typeAliases><plugins><plugin interceptor="com.github.pagehelper.PageInterceptor"><!--默认值为 false,当该参数设置为 true 时,如果 pageSize=0 或者 RowBounds.limit = 0 就会查询出全部的结果--><!--如果某些查询数据量非常大,不应该允许查出所有数据--><property name="pageSizeZero" value="true"/></plugin></plugins><environments default="development"><environment id="development"><transactionManager type="JDBC"/><dataSource type="POOLED"><property name="driver" value="com.mysql.jdbc.Driver"/><property name="url" value="jdbc:mysql://10.59.97.10:3308/windty"/><property name="username" value="windty_opr"/><property name="password" value="windty!234"/></dataSource></environment></environments><databaseIdProvider type="DB_VENDOR"><property name="MySQL" value="mysql" /><property name="Oracle" value="oracle" /></databaseIdProvider><mappers><!--这边可以使用package和resource两种方式加载mapper--><!--<package name="包名"/>--><!--<mapper resource="./mappers/SysUserMapper.xml"/>--><mapper resource="./mappers/CbondissuerMapper.xml"/></mappers></configuration>

下面是解析配置文件的核心方法:

private void parseConfiguration(XNode root) {try {//issue #117 read properties first//解析properties标签,并set到Configration对象中//在properties配置属性后,在Mybatis的配置文件中就可以使用${key}的形式使用了。propertiesElement(root.evalNode("properties"));//解析setting标签的配置Properties settings = settingsAsProperties(root.evalNode("settings"));//添加vfs的自定义实现,这个功能不怎么用loadCustomVfs(settings);//配置类的别名,配置后就可以用别名来替代全限定名//mybatis默认设置了很多别名,参考附录部分typeAliasesElement(root.evalNode("typeAliases"));//解析拦截器和拦截器的属性,set到Configration的interceptorChain中//MyBatis 允许你在已映射语句执行过程中的某一点进行拦截调用。默认情况下,MyBatis 允许使用插件来拦截的方法调用包括://Executor (update, query, flushStatements, commit, rollback, getTransaction, close, isClosed)//ParameterHandler (getParameterObject, setParameters)//ResultSetHandler (handleResultSets, handleOutputParameters)//StatementHandler (prepare, parameterize, batch, update, query)pluginElement(root.evalNode("plugins"));//Mybatis创建对象是会使用objectFactory来创建对象,一般情况下不会自己配置这个objectFactory,使用系统默认的objectFactory就好了objectFactoryElement(root.evalNode("objectFactory"));objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));reflectorFactoryElement(root.evalNode("reflectorFactory"));//设置在setting标签中配置的配置settingsElement(settings);//解析环境信息,包括事物管理器和数据源,SqlSessionFactoryBuilder在解析时需要指定环境id,如果不指定的话,会选择默认的环境;//最后将这些信息set到Configration的Environment属性里面environmentsElement(root.evalNode("environments"));//databaseIdProviderElement(root.evalNode("databaseIdProvider"));//无论是 MyBatis 在预处理语句(PreparedStatement)中设置一个参数时,还是从结果集中取出一个值时, 都会用类型处理器将获取的值以合适的方式转换成 Java 类型。解析typeHandler。typeHandlerElement(root.evalNode("typeHandlers"));//解析MappermapperElement(root.evalNode("mappers"));} catch (Exception e) {throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + e, e);}
}

上面解析流程结束后会生成一个Configration对象,包含所有配置信息,然后会创建一个SqlSessionFactory对象,这个对象包含了Configration对象。

下面是openSession的过程:

private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {Transaction tx = null;try {final Environment environment = configuration.getEnvironment();final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);//获取执行器,这边获得的执行器已经代理拦截器的功能(见下面代码)final Executor executor = configuration.newExecutor(tx, execType);//根据获取的执行器创建SqlSessionreturn new DefaultSqlSession(configuration, executor, autoCommit);} catch (Exception e) {closeTransaction(tx); // may have fetched a connection so lets call close()throw ExceptionFactory.wrapException("Error opening session.  Cause: " + e, e);} finally {ErrorContext.instance().reset();}}
//interceptorChain生成代理类,具体参见Plugin这个类的方法
public Executor newExecutor(Transaction transaction, ExecutorType executorType) {executorType = executorType == null ? defaultExecutorType : executorType;executorType = executorType == null ? ExecutorType.SIMPLE : executorType;Executor executor;if (ExecutorType.BATCH == executorType) {executor = new BatchExecutor(this, transaction);} else if (ExecutorType.REUSE == executorType) {executor = new ReuseExecutor(this, transaction);} else {executor = new SimpleExecutor(this, transaction);}if (cacheEnabled) {executor = new CachingExecutor(executor);}executor = (Executor) interceptorChain.pluginAll(executor);return executor;}

到此为止,我们已经获得了SqlSession,拿到SqlSession就可以执行各种CRUD方法了。

简单总结

对于MyBatis启动的流程(获取SqlSession的过程)这边简单总结下:

  • SqlSessionFactoryBuilder解析配置文件,包括属性配置、别名配置、拦截器配置、环境(数据源和事务管理器)、Mapper配置等;解析完这些配置后会生成一个Configration对象,这个对象中包含了MyBatis需要的所有配置,然后会用这个Configration对象创建一个SqlSessionFactory对象,这个对象中包含了Configration对象;
  • 拿到SqlSessionFactory对象后,会调用SqlSessionFactory的openSesison方法,这个方法会创建一个Sql执行器(Executor),这个Sql执行器会代理你配置的拦截器方法
  • 获得上面的Sql执行器后,会创建一个SqlSession(默认使用DefaultSqlSession),这个SqlSession中也包含了Configration对象,所以通过SqlSession也能拿到全局配置;
  • 获得SqlSession对象后就能执行各种CRUD方法了。

SQL的具体执行流程见后续博客。

一些重要类总结:

  • SqlSessionFactory
  • SqlSessionFactoryBuilder
  • SqlSession(默认使用DefaultSqlSession)
  • Plugin、InterceptorChain的pluginAll方法

附录

MyBatis内置别名转换

//TypeAliasRegistry
registerAlias("string", String.class);registerAlias("byte", Byte.class);
registerAlias("long", Long.class);
registerAlias("short", Short.class);
registerAlias("int", Integer.class);
registerAlias("integer", Integer.class);
registerAlias("double", Double.class);
registerAlias("float", Float.class);
registerAlias("boolean", Boolean.class);registerAlias("byte[]", Byte[].class);
registerAlias("long[]", Long[].class);
registerAlias("short[]", Short[].class);
registerAlias("int[]", Integer[].class);
registerAlias("integer[]", Integer[].class);
registerAlias("double[]", Double[].class);
registerAlias("float[]", Float[].class);
registerAlias("boolean[]", Boolean[].class);registerAlias("_byte", byte.class);
registerAlias("_long", long.class);
registerAlias("_short", short.class);
registerAlias("_int", int.class);
registerAlias("_integer", int.class);
registerAlias("_double", double.class);
registerAlias("_float", float.class);
registerAlias("_boolean", boolean.class);registerAlias("_byte[]", byte[].class);
registerAlias("_long[]", long[].class);
registerAlias("_short[]", short[].class);
registerAlias("_int[]", int[].class);
registerAlias("_integer[]", int[].class);
registerAlias("_double[]", double[].class);
registerAlias("_float[]", float[].class);
registerAlias("_boolean[]", boolean[].class);registerAlias("date", Date.class);
registerAlias("decimal", BigDecimal.class);
registerAlias("bigdecimal", BigDecimal.class);
registerAlias("biginteger", BigInteger.class);
registerAlias("object", Object.class);registerAlias("date[]", Date[].class);
registerAlias("decimal[]", BigDecimal[].class);
registerAlias("bigdecimal[]", BigDecimal[].class);
registerAlias("biginteger[]", BigInteger[].class);
registerAlias("object[]", Object[].class);registerAlias("map", Map.class);
registerAlias("hashmap", HashMap.class);
registerAlias("list", List.class);
registerAlias("arraylist", ArrayList.class);
registerAlias("collection", Collection.class);
registerAlias("iterator", Iterator.class);registerAlias("ResultSet", ResultSet.class);

参考

https://blog.csdn.net/luanlouis/article/details/40422941

MyBatis启动流程分析相关推荐

  1. 解析并符号 读取dll_Spring IOC容器之XmlBeanFactory启动流程分析和源码解析

    一. 前言 Spring容器主要分为两类BeanFactory和ApplicationContext,后者是基于前者的功能扩展,也就是一个基础容器和一个高级容器的区别.本篇就以BeanFactory基 ...

  2. Zygote进程启动流程分析

    文中的源代码版本为api23 Zygote进程启动流程分析 先说结论,zygote进程启动过程中主要做了下面这些事情: 启动DVM虚拟机 预加载部分资源,如一些通用类.通用资源.共享库等 启动syst ...

  3. c++builder启动了怎么停止_App 竟然是这样跑起来的 —— Android App/Activity 启动流程分析...

    在我的上一篇文章: AJie:按下电源键后竟然发生了这一幕 -- Android 系统启动流程分析​zhuanlan.zhihu.com 我们分析了系统在开机以后的一系列行为,其中最后一阶段 AMS( ...

  4. SpringBoot启动流程分析(四):IoC容器的初始化过程

    SpringBoot系列文章简介 SpringBoot源码阅读辅助篇: Spring IoC容器与应用上下文的设计与实现 SpringBoot启动流程源码分析: SpringBoot启动流程分析(一) ...

  5. Exynos4412 Uboot 移植(二)—— Uboot 启动流程分析

    uboot启动流程分析如下: 第一阶段: a -- 设置cpu工作模式为SVC模式 b -- 关闭中断,mmu,cache v -- 关看门狗 d -- 初始化内存,串口 e -- 设置栈 f -- ...

  6. bootloader启动流程分析

    bootloader启动流程分析 1.Bootloader的概念和作用 Bootloader是嵌入式系统的引导加载程序,它是系统上电后运行的第一段程序.在完成对系统的初始化任务之后,它会将Flash中 ...

  7. Mybatis执行流程分析_自定义简易Mybatis框架

    自定义简易Mybatis框架 Mybatis执行流程分析 Mybatis代码编写流程: Mybatis配置文件加载过程: 需求分析及技术概述 根据上述的功能结构图, 得出如下需求: 1. 需要具有配置 ...

  8. NameNode之启动流程分析

    NameNode启动流程分析 public staticvoid main(Stringargv[]) throws Exception { if (DFSUtil.parseHelpArgument ...

  9. springboot中获得app_Spring Boot 应用程序启动流程分析

    SpringBoot 有两个关键元素: @SpringBootApplication SpringApplication 以及 run() 方法 SpringApplication 这个类应该算是 S ...

最新文章

  1. 解决一个坑爹的mininet的pingall失败的问题(自己编译安装openvswitch后)
  2. AsyncDisplayKit
  3. STL源代码分析(ch2 内存分配)jjalloc.h
  4. 遥远的,理想与现实的完美统一——听完华大基因的宣讲,有点小激动···
  5. SCI录用的最后一步——答复审稿人的策略和答复信的写作技巧
  6. java wate_Trapping Rain Water leetcode java
  7. jsonp原生js跨域拿新浪数据插件封装【可扩展】
  8. Web进程被kill掉后线程还在运行怎么办?
  9. mac的 上传到linux服务器地址,【mac 怎么登录到 linux 服务器并传输文件?】-看准网...
  10. 如何在 Mac 上的调度中心中查看打开的窗口和空间?
  11. 170705、springboot编程之自定义properties
  12. paip.连接access2003数据库python3.3以及php5对比
  13. python做社会网络分析_利用GooSeeker分词、Ucient和NetDraw进行社会网络分析
  14. 基于基于jsp+mysql+Spring+mybatis的SSM汽车保险理赔管理系统设计和实现
  15. 电脑的热点手机连接不上怎么办
  16. C++ 完全平方数
  17. 小鸟飞行游戏【附源码】
  18. 802.1x EAP(证书)、PEAP(证书、EAP-MSCHAP v2)认证配置(NPS、组策略)
  19. 机器人在gazebo中使用四轮差速仿真模型时,转向不明显?
  20. javamail 读取/发送exchange邮件

热门文章

  1. 快速安装 Moodle 指南
  2. redis——通过redis实现服务器崩溃等数据恢复
  3. redis cluster管理工具redis-trib.rb详解
  4. mysql MHA 集群搭建
  5. LeetCode 563. Binary Tree Tilt
  6. 《C和指针》——指向数组的指针(逐个移动和逐行的区别)
  7. 【python】随机采样的两种方法
  8. Linux—目录文件属性和权限管理详解
  9. 华科05年计算机考研复试机试
  10. DateTimePicker控件 1130