MyBatis架构设计及源代码分析系列(一):MyBatis架构
2015-07-16 00:00
639 查看
如果不太熟悉MyBatis使用的请先参见MyBatis官方文档,这对理解其架构设计和源码分析有很大好处。
TheMyBatisdatamapperframeworkmakesiteasiertousearelationaldatabasewithobject-orientedapplications.MyBatiscouplesobjectswithstoredproceduresorSQLstatementsusingaXMLdescriptororannotations.SimplicityisthebiggestadvantageoftheMyBatisdatamapperoverobjectrelationalmappingtools.
而在其官方文档中介绍“WhatisMyBaits”中说到
MyBatisisafirstclasspersistenceframeworkwithsupportforcustomSQL,storedproceduresandadvancedmappings.MyBatiseliminatesalmostalloftheJDBCcodeandmanualsettingofparametersandretrievalofresults.MyBatiscanusesimpleXMLorAnnotationsforconfigurationandmapprimitives,MapinterfacesandJavaPOJOs(PlainOldJavaObjects)todatabaserecords.
ORM是Object和Relation之间的映射,包括Object->Relation和Relation->Object两方面。Hibernate是个完整的ORM框架,而MyBatis完成的是Relation->Object,也就是其所说的datamapperframework。关于ORM的一些设计思路和细节可以参见MartinFlow《企业应用架构模式》一书中的ORM章节,MyBatis并不刻意于完成ORM(对象映射)的完整概念,而是旨在更简单、更方便地完成数据库操作功能,减轻开发人员的工作量,我想这对于应用系统来说也是最实用的,相信用Hibernate的都受过它的痛苦,而用过MyBatis的都会感觉它很简捷轻松。
而下面是MyBatis源码包对应的架构图
下面以“功能流程角度的架构图”来简要地分析下各层的架构,在后面系列文章中将有专题来深入解析MyBatis重要的功能点。
Stringresource="org/mybatis/example/mybatis-config.xml";
SqlSessionFactorysqlSessionFactory=newSqlSessionFactoryBuilder().build(inputStream);
try{
}finally{
}
SqlSessionFactory、SqlSession这是MyBatis接口层的核心类,尤其是SqlSession,是实现所有数据库操作的API,这几个类都是org.apache.ibatis.session包下的,这个包的主体类结构图如下
Configuration是MyBatis中相当重要的一个类,可以这么说,如果理解了其中的所有参数的意义,不仅清楚地知道MyBatis提供的所有配置项,还理解了MyBatis的内部核心运行原理,当然要真正理解这些参数的意义及实现,还需要阅读完完整的MyBatis框架之后才能做到。
由上图可以看到,Configuration对象与DefaultSqlSessionFactory是1:1的关联关系,这也就意味着在一个DefaultSqlSessionFactory衍生出来的所有SqlSession作用域里,Configuration对象是全局唯一的。同时SqlSessionFactory提供了getConfiguration()接口来公开Configuration对象,因此开发者除了配置文件之外,还可以在程序里动态更改Configuration的属性项以达到动态调整的目的,但此时不仅要考虑到执行完reset,同时还要考虑在修改过程中会可能影响到其他SqlSession的执行。
SqlMapConfig.xml
SqlMap.xml
SqlMapConfig.xml是在XMLConfigBuilder类中完成解析的,其类图关系大致如下
我们知道XML有两种解析方式:一是DOM,另一个是SAX,MyBatis使用的是org.wrc.dom——JDK提供的文档对象模型(DOM)接口(SqlMapConfig.xml并不大,所以DOM方式并没有什么效率损耗,JDK也提供了SAX模型接口org.xml.sax,这两个都是JAXP的组件API),以及JDK官方提供的javax.xml.xpath.XPath来作为XML路径寻找组件。
SqlMap.xml是在XMLMapperBuilder中解析完成的,其中把对Statement的解析(即SqlMap.xml中SELECT|INSERT|UPDATE|DELETE定义部分)委托给XMLStatementBuilder来完成。SqlMap.xml的解析比较复杂的,涉及到PreparedMapping、ResultMapping、LanguageDriver、Discriminator、缓存、自动映射等一系列对象的构造,这里暂时略过,后面专题分析。
在上图中我列出了Executor中方法的参数,而在其子类中就没有明确写出。从上图中可以看到,Executor主要提供了
QUERY|UPDATE(INSERT和DELETE也是使用UPDATE),从方法定义中可看到,它需要MappedStatement、parameter、resultHandler这几个实例对象,这几个也是SQL执行的主要部分,详细实现在后面专题中再介绍。
事务提交/回滚,这委托给Transaction对象来完成。
缓存,createCacheKey()/isCached()。
延迟加载,deferload()。
关闭,close(),主要是事务回滚/关闭。
BaseExecutor的属性表明:它内部维护了localCache来localOutputParameterCache来处理缓存,至于这缓存保存的是什么,这后面专题再说。以及线程安全的延迟加载列表deferredLoads、事务对象Transaction。
BatchExecutor的属性已经表明:它内部维护了StatementList批量提交并通过batchResultList保存执行结果。
ResueExecutor的属性及方法表明:它内部维护了java.sql.Statement对象缓存,以重用Statement对象(对于支持预编译的数据库而言,在创建PreparedStatement时需要发送一次数据库请求预编译,而重用Statement对象主要是减少了这次预编译的网路开销)。
下面以SqlSession.selectList为例,画出SQL执行的时序图(点击下方的图片查看大图,部分分支有所简化)
在org.apache.ibatis.logging里还有个比较特殊的包jdbc,这不是按字面意义理解把日志通过jdbc记录到数据库里,而是将jdbc操作以开发者配置的日志框架打印出来,这也就是我们在开发阶段常用的跟踪SQL语句、传入参数、影响行数这些重要的调试信息。
SESSION或STATEMENT作用域级别的缓存,默认是SESSION,BaseExecutor中根据MappedStatement的Id、SQL、参数值以及rowBound(边界)来构造CacheKey,并使用BaseExccutor中的localCache来维护此缓存。
全局的二级缓存,通过CacheExecutor来实现,其委托TransactionalCacheManager来保存/获取缓存,这个全局二级缓存比较复杂,后面还需要专题分析,至于其缓存的效率以及应用场景也留到那时候再分析。
后续将对MyBatis各个部分做详细的设计及源代码分析,由于读取和解析SqlMapConfig.xml和SqlMap.xml的逻辑与各个模块的相关性较强,因此将把这部分内容与在各模块组合在一起分析。
一、概述
MyBatis并不是一个完整的ORM框架,其官方首页是这么介绍自己而在其官方文档中介绍“WhatisMyBaits”中说到
ORM是Object和Relation之间的映射,包括Object->Relation和Relation->Object两方面。Hibernate是个完整的ORM框架,而MyBatis完成的是Relation->Object,也就是其所说的datamapperframework。关于ORM的一些设计思路和细节可以参见MartinFlow《企业应用架构模式》一书中的ORM章节,MyBatis并不刻意于完成ORM(对象映射)的完整概念,而是旨在更简单、更方便地完成数据库操作功能,减轻开发人员的工作量,我想这对于应用系统来说也是最实用的,相信用Hibernate的都受过它的痛苦,而用过MyBatis的都会感觉它很简捷轻松。
二、整体架构
下面是从功能流程层次描述MyBatis的整体架构图而下面是MyBatis源码包对应的架构图
下面以“功能流程角度的架构图”来简要地分析下各层的架构,在后面系列文章中将有专题来深入解析MyBatis重要的功能点。
1、接口层
我们知道,在不考虑与Spring集成的情况下,使用MyBatis执行数据库操作的代码如下InputStreaminputStream=Resources.getResourceAsStream(resource);
SqlSessionsession=sqlSessionFactory.openSession();
Blogblog=session.selectOne("org.mybatis.example.BlogMapper.selectBlog",101);
session.close();
SqlSessionFactory、SqlSession这是MyBatis接口层的核心类,尤其是SqlSession,是实现所有数据库操作的API,这几个类都是org.apache.ibatis.session包下的,这个包的主体类结构图如下
Configuration是MyBatis中相当重要的一个类,可以这么说,如果理解了其中的所有参数的意义,不仅清楚地知道MyBatis提供的所有配置项,还理解了MyBatis的内部核心运行原理,当然要真正理解这些参数的意义及实现,还需要阅读完完整的MyBatis框架之后才能做到。
由上图可以看到,Configuration对象与DefaultSqlSessionFactory是1:1的关联关系,这也就意味着在一个DefaultSqlSessionFactory衍生出来的所有SqlSession作用域里,Configuration对象是全局唯一的。同时SqlSessionFactory提供了getConfiguration()接口来公开Configuration对象,因此开发者除了配置文件之外,还可以在程序里动态更改Configuration的属性项以达到动态调整的目的,但此时不仅要考虑到执行完reset,同时还要考虑在修改过程中会可能影响到其他SqlSession的执行。
2、核心层
2.1配置解析
在应用启动的时候,MyBatis解析两种配置文件SqlMapConfig.xml
SqlMap.xml
SqlMapConfig.xml是在XMLConfigBuilder类中完成解析的,其类图关系大致如下
我们知道XML有两种解析方式:一是DOM,另一个是SAX,MyBatis使用的是org.wrc.dom——JDK提供的文档对象模型(DOM)接口(SqlMapConfig.xml并不大,所以DOM方式并没有什么效率损耗,JDK也提供了SAX模型接口org.xml.sax,这两个都是JAXP的组件API),以及JDK官方提供的javax.xml.xpath.XPath来作为XML路径寻找组件。
SqlMap.xml是在XMLMapperBuilder中解析完成的,其中把对Statement的解析(即SqlMap.xml中SELECT|INSERT|UPDATE|DELETE定义部分)委托给XMLStatementBuilder来完成。SqlMap.xml的解析比较复杂的,涉及到PreparedMapping、ResultMapping、LanguageDriver、Discriminator、缓存、自动映射等一系列对象的构造,这里暂时略过,后面专题分析。
2.2SQL执行
MyBatis中Executor是的核心,围绕着它完成了数据库操作的完整过程。下面是Executor的类图在上图中我列出了Executor中方法的参数,而在其子类中就没有明确写出。从上图中可以看到,Executor主要提供了
QUERY|UPDATE(INSERT和DELETE也是使用UPDATE),从方法定义中可看到,它需要MappedStatement、parameter、resultHandler这几个实例对象,这几个也是SQL执行的主要部分,详细实现在后面专题中再介绍。
事务提交/回滚,这委托给Transaction对象来完成。
缓存,createCacheKey()/isCached()。
延迟加载,deferload()。
关闭,close(),主要是事务回滚/关闭。
BaseExecutor的属性表明:它内部维护了localCache来localOutputParameterCache来处理缓存,至于这缓存保存的是什么,这后面专题再说。以及线程安全的延迟加载列表deferredLoads、事务对象Transaction。
BatchExecutor的属性已经表明:它内部维护了StatementList批量提交并通过batchResultList保存执行结果。
ResueExecutor的属性及方法表明:它内部维护了java.sql.Statement对象缓存,以重用Statement对象(对于支持预编译的数据库而言,在创建PreparedStatement时需要发送一次数据库请求预编译,而重用Statement对象主要是减少了这次预编译的网路开销)。
下面以SqlSession.selectList为例,画出SQL执行的时序图(点击下方的图片查看大图,部分分支有所简化)
3、基础层
3.1、logging:
MyBatis使用了自己定义的一套logging接口,根据开发者常使用的日志框架——Log4j、Log4j2、ApacheCommonsLog、java.util.logging、slf4j、stdout(控制台)——分别提供了适配器。由于各日志框架的Log级别分类法有所不同(比如java.util.logging.Level提供的是All、FINEST、FINER、FINE、CONFIG、INFO、WARNING、SEVERE、OFF这九个级别,与通常的日志框架分类法不太一样),MyBatis统一提供trace、debug、warn、error四个级别,这基本与主流框架分类法是一致的(相比而言缺少Info,也许MyBatis认为自己的日志要么是debug需要的,要么就至少是warn,没有Info的必要)。在org.apache.ibatis.logging里还有个比较特殊的包jdbc,这不是按字面意义理解把日志通过jdbc记录到数据库里,而是将jdbc操作以开发者配置的日志框架打印出来,这也就是我们在开发阶段常用的跟踪SQL语句、传入参数、影响行数这些重要的调试信息。
3.2、IO
MyBatis里的IO主要是包含两大功能:提供读取资源文件的API、封装MyBatis自身所需要的ClassLoader和加载顺序。3.3、reflection
在MyBatis如参数处理、结果映射这些大量地使用了反射,需要频繁地读取Class元数据、反射调用get/set,因此MyBatis提供了org.apache.ibatis.reflection对常见的反射操作进一步封装,以提供更简洁方便的API。比如我们reflect时总是要处理异常(IllegalAccessException、NoSuchMethodException),MyBatis统一处理为自定义的RuntimeException,减少代码量。3.4、exceptions
在以Spring为代表的开源框架中,对于应用程序中无法进一步处理的异常大都转成RuntimeException来方便调用者操作,另外如频繁遇到的SQLException,JDK约定其是个Exception,从JDK的角度考虑,强制要求开发者捕获SQLException是为了能在catch/finally中关闭数据库连接,而Spring之类的框架为开发者做了资源管理的事情,自然就不需要开发者再烦心SQLException,因此封装转换成RuntimeException。MyBatis的异常体系不复杂,org.apache.ibatis.exceptions下就几个类,主要被使用的是PersistenceException。3.5、缓存
缓存是MyBatis里比较重要的部分,有两种缓存:SESSION或STATEMENT作用域级别的缓存,默认是SESSION,BaseExecutor中根据MappedStatement的Id、SQL、参数值以及rowBound(边界)来构造CacheKey,并使用BaseExccutor中的localCache来维护此缓存。
全局的二级缓存,通过CacheExecutor来实现,其委托TransactionalCacheManager来保存/获取缓存,这个全局二级缓存比较复杂,后面还需要专题分析,至于其缓存的效率以及应用场景也留到那时候再分析。
3.6、数据源/连接池
MyBatis自身提供了一个简易的数据源/连接池,在org.apache.ibatis.datasource下,后面专题分析。主要实现类是PooledDataSource,包含了最大活动连接数、最大空闲连接数、最长取出时间(避免某个线程过度占用)、连接不够时的等待时间,虽然简单,却也体现了连接池的一般原理。阿里有个“druid”项目,据他们说比proxool、c3p0的效率还要高,可以学习一下。3.7事务
MyBatis对事务的处理相对简单,TransactionIsolationLevel中定义了几种隔离级别,并不支持内嵌事务这样较复杂的场景,同时由于其是持久层的缘故,所以真正在应用开发中会委托Spring来处理事务实现真正的与开发者隔离。分析事务的实现是个入口,借此可以了解不扫JDBC规范方面的事情。后续将对MyBatis各个部分做详细的设计及源代码分析,由于读取和解析SqlMapConfig.xml和SqlMap.xml的逻辑与各个模块的相关性较强,因此将把这部分内容与在各模块组合在一起分析。
相关文章推荐
- 张升:农业银行的分布式架构应用实践与展望
- HTML5 Web Workers之网站也能多线程的实现
- 架构之重构的12条军规
- 我的架构师梦想日记
- QQ游戏百万人同时在线服务器架构实现
- 实时处理日均50亿会话,解析Twitter Answers的架构
- How-to: enable hbase ACL and verify
- (linux服务器架构设计 金融行业CMS系统)第一篇 【规划思路】
- iOS 操作系统架构
- 一种更清晰的Android架构
- 美团推荐算法实践:机器学习重排序模型成亮点
- 一步步构建大型网站架构
- 高性能网站性能优化与系统架构(ZT)
- 【转载】12306铁道部订票网站性能分析
- 网站
- 构架高性能WEB网站的几点知识
- 【经验】对教务处网站的抓包分析并GET教务处照片
- SOA&RESTful软件架构
- hadoop 学习笔记(hadoop架构)
- 如何检测网站死链接?