`

MyBatis整体预览(一)

 
阅读更多

来源:http://blog.csdn.net/jdream314/article/details/7462441

 

题记:最近在工作之余分析了一下MyBatis的源码,促使我阅读源码的原因是为了实现MyBatis在物理上的分页。我们知道,MyBatis是在逻辑上的分页,通过用户的查询,将结果缓存下来,在查看是否传递了RowBounds对象,在查看里面的offsetlimit值,通过这两个值,从返回的结果集合中截取位于期间的值。但是这样并不是很好,可以想想,如果假设查询的数据量很大,但是有用的可以是前几条,这未免有点太浪费了。在之前,也在网上查了一下实现分页的方法,最常用的就是添加MyBatis插件,实现Interceptor接口,拦截StatementHandler接口中的prepare方法,后面会介绍为什么拦截这个接口的这个方法。在拦截ResultSetHandler接口的handlerResultSet方法,后面也会对其缘由进行介绍。但是这中方法虽然可以添加分页的SQL语句,但是并没有将分页的offsetlimit的值让Mybatis动态的添加到SQL中去,有人会说,可以在拦截StatementHandler接口的时候我们将它们拼装上去。但是这样会容易出现SQL注入的问题。所以这样不得不使我进一步的了解MyBatis的内部原理。本文将就一下几个方面对MyBatis的内部实现进行分析。

mybatis源码结构图

 

数据管家——Configuration:

 

    MyBatis在运行期的基本上所有的数据都会汇总到这个类。它的初始数据是来自开发人员配置在configurationxml配置文件。通过用户配置的environments来获得系统运行的数据库环境,如事物管理以及数据源。下面给出了最基本的配置:

 

  1. <configuration>  
  2. <environments default="development">  
  3. <environment id="development">  
  4. <transactionManager type="JDBC" />  
  5. <dataSource type="POOLED">  
  6. <property name="driver" value="com.mysql.jdbc.Driver"/>  
  7. <property name="url" value="jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=GBK"/>  
  8. <property name="username" value="root"/>  
  9. <property name="password" value="root"/>  
  10. </dataSource>  
  11. </environment>  
  12. </environments>  
  13. <mappers>  
  14. <mapper resource="com/bieber/mybatis/io/user-mapper.xml"/>  
  15. </mappers>  
  16. </configuration>  
<configuration>
<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://localhost:3306/test?useUnicode=true&characterEncoding=GBK"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="com/bieber/mybatis/io/user-mapper.xml"/>
</mappers>
</configuration>


 

 

这些配置对于MyBatis需要做哪些工作呢?通过阅读Configuration的源码会发现,Mybatis其实为configuration标签下面的子标签都有一个对应的变量来进行存储,例如:

 

  1. protected final TypeHandlerRegistry typeHandlerRegistry = new TypeHandlerRegistry();  
protected final TypeHandlerRegistry typeHandlerRegistry = new TypeHandlerRegistry();


 

 

则是存储<typeHandlers></typeHandlers>标签下面配置的所有信息。其他的也类似可以找到。负责创建Configuration对象的则是XMLConfigurationBuilder,这里将完成从配置的XML数据映射到Configuration对象的数据。通过一下方法完成数据的映射:

  1. private void parseConfiguration(XNode root) {  
  2.     try {  
  3.     propertiesElement(root.evalNode("properties"));         typeAliasesElement(root.evalNode("typeAliases"));  
  4.         pluginElement(root.evalNode("plugins"));  
  5.         objectFactoryElement(root.evalNode("objectFactory"));  
  6.                   objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));  
  7.       settingsElement(root.evalNode("settings"));  
  8.       environmentsElement(root.evalNode("environments"));  
  9.       databaseIdProviderElement(root.evalNode("databaseIdProvider"));  
  10.       typeHandlerElement(root.evalNode("typeHandlers"));  
  11.       mapperElement(root.evalNode("mappers"));  
  12.     } catch (Exception e) {  
  13.       throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + e, e);  
  14.     }  
  15.   }  
private void parseConfiguration(XNode root) {
    try {
	propertiesElement(root.evalNode("properties"));       	typeAliasesElement(root.evalNode("typeAliases"));
      	pluginElement(root.evalNode("plugins"));
      	objectFactoryElement(root.evalNode("objectFactory"));
  				  objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));
      settingsElement(root.evalNode("settings"));
      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);
    }
  }


 

可以到,它为每个元素都对应了一个处理方法,这些方法将负责解析我们配置的XML文件。这里面我主要跟踪了几个方法的执行

mapperElementtypeHandlerElementtypeAliasesElementenvironmentsElement)

mapperElement——ORM

 

       我们知道,MyBatis支持注解形式和XML形式的ORM配置。那么当然将会有两个类来处理这两种行为,它们分别是XMLMapperBuilderMapperAnnotationBuilder,它们分别处理什么类型,我看我就不用说了。通过解析configuration/mappers元素来获得ORM配置信息。

1)XML方式的ORM配置和方式,当我们在mappers/mapper的属性中配置了url或者是resource信息的时候将触发MyBatis采用XML的方式进行处理,并读取你指定的mapper路径。在XMLMapperBuilder类中有如下方法:

 

  1. private void configurationElement(XNode context) {  
  2.   
  3.     try {  
  4.   
  5.       String namespace = context.getStringAttribute("namespace");  
  6.   
  7.       builderAssistant.setCurrentNamespace(namespace);  
  8.   
  9.       cacheRefElement(context.evalNode("cache-ref"));  
  10.   
  11.       cacheElement(context.evalNode("cache"));  
  12.   
  13.       parameterMapElement(context.evalNodes("/mapper/parameterMap"));  
  14.   
  15.       resultMapElements(context.evalNodes("/mapper/resultMap"));  
  16.   
  17.       sqlElement(context.evalNodes("/mapper/sql"));  
  18.   
  19.       buildStatementFromContext(context.evalNodes("select|insert|update|delete"));  
  20.   
  21.     } catch (Exception e) {  
  22.   
  23.       throw new RuntimeException("Error parsing Mapper XML. Cause: " + e, e);  
  24.   
  25.     }  
  26.   
  27.   }  
private void configurationElement(XNode context) {

    try {

      String namespace = context.getStringAttribute("namespace");

      builderAssistant.setCurrentNamespace(namespace);

      cacheRefElement(context.evalNode("cache-ref"));

      cacheElement(context.evalNode("cache"));

      parameterMapElement(context.evalNodes("/mapper/parameterMap"));

      resultMapElements(context.evalNodes("/mapper/resultMap"));

      sqlElement(context.evalNodes("/mapper/sql"));

      buildStatementFromContext(context.evalNodes("select|insert|update|delete"));

    } catch (Exception e) {

      throw new RuntimeException("Error parsing Mapper XML. Cause: " + e, e);

    }

  }


 

 

这个方法便是读取你mapper文件中所有制的ORM信息。该方法将通过调用XMLMapperBuilderparse()方法触发。

    2)注解方式配置ORM信息加载,当你配置了mappers/package或者在mapper里面配置了class属性的时候将触发信息的读取,具体的过程我就再描述了,基本和上面差不多,只是读取的是注解的信息。

    注意:MyBatis优先处理的是注解形式的方式,并且在mapper配置中,当配置了多个属性时,resource属性优先处理。

    那么在这样处理后Configuration会得到怎样的数据呢?通过这些处理在Configuration里面将会获得几个主要的变量值:sqlFragmentsresultMapsmappedStatements。其中sqlFragments就是我们定义在mapper里面的sql标签或者注解的内容,而resultMaps也是定义在mapper里面或者注解的resultMap内容。最重要的是mappedStatements,这是ORM的最关键部分。它里面通过键值对的方式存储,key这是我们配置的id属性加上namespace,而value则是MappedStatement对象,这个对象这就对应了我们配置的select/update/delete/insert标签的值。

    MappedStatement对象包含这条slq语句的ID,执行的类型(Inser,update,delte,select)statementType(指定产生Statement的类型,如PreparedStatement,还有一个就是SqlSource接口的子类对象,在MyBatis中有两种SqlSource,一种是动态的,另一种是静态的。不用解释,应该都明白,一个是生成动态SQL用的,另一个这是简单静态的SQL。在SqlSource中,包括你定义的SQL语句,以及引入的外部SQL语句块。MappedStatement最后还要包括一个重要的信息,这就是ParameterMap,这直接关系你定义的SQL语句中通过#propertyName}定义的动态填充值。如果你的是一个POJO对象,那么MyBatis将会通过反射获得这个对象的属性,并依次填入到对应的propertyName所在的位置。

    注意:此时的MappedStatement中的SQL语句还是带有#{propertyName}这样占位符的字符串,还并没有解析成待问号(?)的占位符。要执行该操作是在执行具体的数据库操作的时候才替换成(?),只是为了很好的找到这个propertyName所对应的值所在的位置。

以上就将整个SqlSession的初始化过程所做的操作进行了解剖。完成这些操作之后,那么就等待用户触发对数据库的操作了。

   后续将会给出,MyBatis是如何触发用户自定义的插件的过程以及开发自己的TypeHandlerMyBatis允许用户的插件可以拦截ParameterHandlerResultSetHandlerStatementHandlerExecutor接口,从而进行一些操作。

分享到:
评论

相关推荐

    MybatisX 快速开发插件

    总的来说,MybatisX快速开发插件是提升Mybatis开发效率的得力助手,它简化了许多繁琐的操作,使得开发者能够更加专注于业务逻辑的实现,提高了整体的开发质量和效率。对于那些频繁使用Mybatis的团队或个人,MybatisX...

    这是一款高度自定义代码生成idea插件,目前提供的 模板是依托于mybatis-flex 代码提示、自动APT,SQL预览等特性

    IDEA作为一款强大的Java集成开发环境,提供了丰富的插件来扩展其功能,其中“高度自定义代码生成idea插件”就是针对Mybatis-Flex框架的一个优秀工具。这款插件旨在帮助开发者更高效地生成代码,减少重复劳动,从而...

    idea-mybatis插件包

    7. **开发效率**:通过使用此插件,开发者可以更快速地定位和修改MyBatis代码,减少出错的可能性,提升整体的开发效率和代码质量。 8. **兼容性**:由于是针对free-idea设计的,所以这个插件应能与IntelliJ IDEA的...

    Mybatis_auto_tools.rar_mybatis 工具

    Mybatis Auto Tools是一款专为简化Mybatis开发流程而设计的自动化工具。Mybatis是一个轻量级的Java持久层框架,它允许开发者通过SQL映射文件和接口定义来处理数据库交互,极大地提高了开发效率。这款工具进一步提升...

    mybatis自动生成工具

    mybatis自动生成工具能够生成带有中文注释的代码,这在多语言环境中尤其方便,有助于提高团队的整体开发效率。 在实际使用中,mybatis自动生成工具可能包含以下功能: 1. 数据库连接配置:用户需要提供数据库连接...

    mybatis-plus-generator-ui

    Mybatis-Plus-Generator-UI 是一个基于 Mybatis-Plus 的图形...通过集成 Mybatis-Plus-Generator-UI,开发团队能够快速生成规范化的代码,从而将更多精力投入到业务逻辑的设计与优化上,提高整体项目开发的质量和速度。

    springboot+mybatis+gradle+thymeleaf+springsecurity

    在本项目中,我们主要探讨的是如何将四个关键的Java技术框架——Spring Boot、MyBatis、Spring Security以及Thymeleaf——集成到一个应用程序中。这是一个常见的技术栈选择,适用于构建高效、安全且易于维护的Web...

    My Blog 是由 SpringBoot + Mybatis + Thymeleaf 等技术实现的 Java 博客系统

    在My Blog中,SpringBoot负责整体架构的搭建,提供依赖注入、日志、安全控制等一系列基础服务。 Mybatis作为持久层框架,它与SpringBoot结合,实现了数据库操作的便捷性。Mybatis允许开发者直接编写SQL语句,避免了...

    SpringBoot+Mybatis+Thymeleaf等技术实现的Java博客系统.zip

    【标题】"SpringBoot+Mybatis+Thymeleaf等技术实现的Java博客系统"是一个典型的Java后端开发项目,采用现代Web开发框架和技术栈。这个项目的核心是将SpringBoot、Mybatis和Thymeleaf这三大技术进行整合,构建一个...

    SpringMVC +Spring +Mybatis + LarryMS + Layui的通用后台管理系统OneManageV1.0.0

    首个由One源码官方出品的一款基于SpringMVC +Spring +Mybatis + LarryMS + Layui的通用后台管理系统 ,系统具备了用户管理,角色管理,菜单管理等基本功能,可以在此基础上进行二次开发,首个版本在2017年的最后一...

    基于SpringMVC+Spring+MyBatis开发的个人博客网站-毕业设计.zip

    一、关于项目 该博客是基于SSM实现的个人博客系统,适合初学SSM和个人博客制作的同学学习。主要技术架构包括Maven、SpringMVC、Spring、MyBatis、Thymeleaf、Redis等。前端采用Bootstarp和Semantic UI。 二、使用...

    spring-bootstrap:spring 4.0,thymeleaf 和 mybatis 集成

    Thymeleaf的模板功能可以让前端开发更加直观,而MyBatis则提供对数据库的强大操作能力,Spring 4.0作为整体框架的粘合剂,负责依赖注入、AOP和事务管理。 在项目"spring-bootstrap-master"中,可能包含了以下内容:...

    项目说明1

    在项目中,Spring 被用来进行整体的应用管理和事务控制,以及与其它框架如Hibernate和MyBatis的集成。 3. **Hibernate**: Hibernate 是一个持久化框架,它简化了数据库操作,通过对象关系映射(ORM)将Java对象与...

    基于java的-131-jspm整体衣柜定制系统-源码.zip

    在Java的环境中,整体衣柜定制系统可能会采用Spring框架作为后端开发的基础,利用Spring Boot简化项目的初始化和配置,同时结合MyBatis或JPA进行数据访问层的实现。前端可能使用Thymeleaf或JSP作为视图模板,结合...

    vue.js游戏商城系统(源码+数据库)190914

    整体而言,这个Vue.js游戏商城系统结合了多种技术,构建了一个完整的线上游戏交易和信息交流平台,涵盖了用户身份管理、商品展示、交易处理和信息传递等多个方面。对于学习和实践Web开发的开发者来说,这是一个很好...

    MybatisCodeHelperNew-2.8.2.zip

    通过安装并使用MybatisCodeHelperNew,开发者可以在Mybatis项目开发中显著提高代码编写速度,减少出错概率,提升整体开发效率。对于熟悉Mybatis框架的开发者来说,这是一款不容忽视的工具,能够助力他们在代码海洋中...

    jspm高校师生教学科研成果传报系统 程序

    同时,可能还具备统计分析功能,帮助管理部门了解科研活动的整体情况,以便做出决策。 系统的启动文件`start.bat`通常是一个批处理脚本,用于一键启动整个系统服务,包括数据库连接、服务器配置等。而`jspm高校师生...

    基于ssm微信点餐系统小程序源码数据库文档.zip

    本文将深入探讨一个基于SSM(Spring、SpringMVC、MyBatis)框架的微信点餐系统小程序的实现,以及与其相关的数据库设计与文档。 一、SSM框架解析 1. Spring:作为Java企业级应用的核心框架,Spring提供了依赖注入...

    基于SSM+vue的高校试题管理系统.zip

    整体来看,这是一个涵盖了全栈开发的项目,不仅锻炼了开发者的技术能力,也体现了其对现代Web应用架构和移动端开发的综合理解。通过这个系统,高校能够更加系统化地管理试题资源,提高教学效率,同时为学生提供方便...

    [计算机毕业设计]基于SSM的中国古诗词学习平台(源码 + 演示视频)

    这是一个基于SSM(Spring、SpringMVC、MyBatis)框架构建的中国古诗词学习平台的毕业设计项目。SSM是Java开发Web应用时常用的三大框架,它们分别负责不同的职责:Spring作为整体的依赖注入容器,SpringMVC处理HTTP...

Global site tag (gtag.js) - Google Analytics