我们都知道Mybatis
是一个非常小巧灵活的ORM框架,深受国内广大开发者的喜爱,我们知道它的出现某种程度了是为了消除所有的 JDBC 代码和参数的手工设置以及结果集的封装问题;基于这个一点,我们就可以知道MyBatis
实际上就是对JDBC的封装 ,所以这节我们就来看下MyBatis
是怎样对JDBC封装的,从而可以借鉴学习其他优秀框架在解决问题之初从架构设计层面的思考,然后通过执行流程分析,进一步深刻理解Mybatis
的工作原理
Mybatis的架构设计
首先我们先来了解下MyBatis
的架构设计
MyBatis
总共把功能架构分成了四部分
-
接口层
提供给外部使用的接口API,开发人员通过这些本地
API
来操纵数据库。接口层一接收到调用请求就会调用数据处理层来完成具体的数据处理,Mybatis
提供了两种方式-
传统的方式
下面的这些方法就是在
SqlSession
接口中提供的接口方法
/** * Retrieve a single row mapped from the statement key and parameter. * @param <T> the returned object type * @param statement Unique identifier matching the statement to use. * @param parameter A parameter object to pass to the statement. * @return Mapped object */ <T> T selectOne(String statement, Object parameter); /** * Retrieve a list of mapped objects from the statement key and parameter. * @param <E> the returned list element type * @param statement Unique identifier matching the statement to use. * @param parameter A parameter object to pass to the statement. * @return List of mapped object */ <E> List<E> selectList(String statement, Object parameter); /** * Execute an insert statement with the given parameter object. Any generated * autoincrement values or selectKey entries will modify the given parameter * object properties. Only the number of rows affected will be returned. * @param statement Unique identifier matching the statement to execute. * @param parameter A parameter object to pass to the statement. * @return int The number of rows affected by the insert. */ int insert(String statement, Object parameter); /** * Execute an update statement. The number of rows affected will be returned. * @param statement Unique identifier matching the statement to execute. * @param parameter A parameter object to pass to the statement. * @return int The number of rows affected by the update. */ int update(String statement, Object parameter); /** * Execute a delete statement. The number of rows affected will be returned. * @param statement Unique identifier matching the statement to execute. * @param parameter A parameter object to pass to the statement. * @return int The number of rows affected by the delete. */ int delete(String statement, Object parameter); // 此处省略一万字....
-
Mapper代理的方式
Mapper
代理的方式实际上就是通过创建接口(UserMapper
接口)的代理对象调用接口中的方法,最终执行方法调用是Executor
对象,底层其实还是调用的传统的API
方法;这部分内容我们在源码分析的时候还会在详细分析。
-
-
数据处理层
数据处理层这部分主要就
JDBC
的核心内容了,包括参数映射、类型转换、SQL
解析、SQL
执行以及结果的封装,这部分内容就可以理解成JDBC
的核心内容,这里有几个重要类- ParameterHandler:SQL的参数处理
- ResultSetHandler:结果集处理
- StatementHandler: 封装了JDBC Statement操作,设置参数,转换结果集
- Executor:
MyBatis
的执行器,用于执行增删改查操作
-
框架支撑层
这部分主要是框架抽取出来的通用组件包括数据源管理、事务管理、配置加载和缓存处理;为上层的数据处理层提供最基础的支撑
-
数据源管理
数据源的管理对于持久层的框架来说,可谓是非常的重要,稍有不慎就会浪费大量系统资源,
MyBatis
也对此做了很好的支持,MyBatis
有三种内建的数据源类型UNPOOLED
、POOLED
、JNDI
- UNPOOLED– 这个数据源的实现会每次请求时打开和关闭连接
- POOLED– 这种数据源的实现利用“池”的概念将
JDBC
连接对象组织起来,避免了创建新的连接实例时所必需的初始化和认证时间 - JNDI – 这个数据源实现是为了能在如
EJB
或应用服务器这类容器中使用,容器可以集中或在外部配置数据源,然后放置一个JNDI
上下文的数据源引用。这种已经不用了
通常情况下,我们是会使用
POOLED
的,可以帮他我们节省很多宝贵的系统资源 -
事务管理(transactionManager)
在
MyBatis
中有两种类型的事务管理器(JDBC
/MANAGED
)它通过一个顶层的Transaction
接口以及其不同实现JdbcTransaction 和 ManagedTransaction来实现对事务的管理:- JDBC – 这个配置直接使用了 JDBC 的提交和回滚设施,它依赖从数据源获得的连接来管理事务作用域,对应的实现类
JdbcTransaction
- MANAGED – 这个配置几乎没做什么。它从不提交或回滚一个连接,而是让容器来管理事务的整个生命周期(比如 JEE 应用服务器的上下文),对应的实现类ManagedTransaction
对事务的管理,在和
Spring
整合之后,通常会用Spring
的事务管理器 - JDBC – 这个配置直接使用了 JDBC 的提交和回滚设施,它依赖从数据源获得的连接来管理事务作用域,对应的实现类
-
缓存处理
缓存对于持久层框架来说还是非常重要的,一定程度上可以减少和数据库的交互,
MyBatis
的提供了两种缓存机制,一级缓存和二级缓存- 一级缓存:是
SqlSession
级别的缓存,也就是会话级别的,如果两个相同的查询,第二次的查询会直接先从缓存中去拿,以及缓存也是默认开启的,这部分我们在源码分析的内容里会详细分析 - 二级缓存:是
Mapper
级别的缓存,也就是一个xxx.xml
内的查询是可以共用的,需要手动开启
- 一级缓存:是
-
SQL解析
MyBatis支持两种
SQL
解析的方式,一种xml
、一种是注解;两种方式对于一些基础的CRUD
区别不大,使用注解来映射简单语句会使代码显得更加简洁,但对于稍微复杂一点的语句,Java
注解不仅力不从心,还会让你本就复杂的SQL
语句更加混乱不堪。因此,如果你需要做一些很复杂的操作,最好用 XML 来映射语句
-
-
引导层
这部分是
MyBatis
启动时核心配置文件的方式,严格来说也可以不算在架构层面,不过MyBatis
也是提供了两种方式一个是xml
的方式,也是用的比较多的,一种是使用Java API
的方式比如在配置环境的时候
- xml的方式
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration> <environments default="development"> <environment id="development"> <!--省略--> </environment> </environments> </configuration>
- Java API的方式:
Environment environment = new Environment("development", transactionFactory, dataSource); Configuration configuration = new Configuration(environment);
虽然MyBatis
听过这两种方式,但是一般情况下还是使用xml
的比较方便
小结
这节内容主要从整体架构上分析了Mybatis
的架构设计,实际上是对JDBC的做了一些抽取和封装,主要分成了三层
- API接口层
- 数据处理层
- 框架通用模块
本文来自慕课网 java架构师课程 笔记