框架概览
MyBatis 是支持定制化 SQL、存储过程以及高级映射的优秀的持久层框架,其主要就完成2件事情:
- 封装JDBC操作
- 利用反射打通Java类与SQL语句之间的相互转换
1.架构图
基础架构层大体一共可以分为三层,分别是基础支撑层,数据处理层,接口层。
基础支撑层:负责最基本的基础功能支撑,包括连接管理,失误管理,配置加载,缓存处理。这些都是共用的东西,将他们抽取出来最为最基础的组件,为上层数据处理层提供最基础的支撑。
数据处理层:负责具体的SQL查找,SQL解析,SQL执行,和执行结果的映射处理等。它主要的目的是根据调用的请求完成一次数据库操作。
API接口层:提供给外部使用的接口API,开发人员通过这些本地API来操纵数据库,接口层一接收到请求就会调用数据处理层来完成具体的数据处理。
2.执行流程
3.Mybatis框架主要成员
Configuration:MyBatis所有的配置信息都保存在Configuration
对象之中,配置文件中的大部分配置都会存储到该类中。
SqlSession:作为MyBatis工作的主要顶层API,表示和数据库交互时的会话,完成必要数据库增删改查功能。
Executor:MyBatis执行器,是MyBatis 调度的核心,负责SQL语句的生成和查询缓存的维护。
StatementHandler:封装了JDBC Statement
操作,负责对JDBC statement
的操作,如设置参数等。
ParameterHandler:负责对用户传递的参数转换成JDBC Statement
所对应的数据类型。
ResultSetHandler:负责将JDBC返回的ResultSet
结果集对象转换成List类型的集合。
TypeHandler:负责java数据类型和jdbc数据类型之间的映射和转换。
MappedStatement:MappedStatement
维护一条<select|update|delete|insert>
节点的封装。
SqlSource:负责根据用户传递的parameterObject
,动态地生成SQL语句,将信息封装到BoundSql
对象中,并返回。
BoundSql:表示动态生成的SQL语句以及相应的参数信息。
总体步骤为:
1、加载配置文件到Configuration
2、构建SqlSessionFactory
3、打开SqlSession会话
4、Executor开始处理请求
5、SqlSource解析SQL语句
6、StatementHandler执行SQL语句
7、ParameterHandler设置参数
8、StatementHandler执行SQL语句
9、ResultSetHandler处理结果集
Mybatis初始化
mybatis初始化的过程就是解析配置文件和创建Configuration对象的过程,Configuration类是框架的核心配置类,保存了包括映射器、别名、映射方法等信息。
XMLConfigBuilder对象会进行XML配置文件的解析,实际为configuration
节点的解析操作,首先解析根节点Configuration,然后依次对XML配置文件中的节点进行解析,在解析typeAliases节点时,会对实体类注册别名,在解析environment节点时,根据dartaSrource的配置来创建DataSource对象,在解析mappers节点时,会读取该节点下的所有mapper文件,或者扫描某一个包内的所有类或接口,然后进行一系列的处理过滤掉类只留下mapper接口,最后所有解析的结果会存到configuration对象中。
// XMLConfigBuilder类
public Configuration parse() {
if (parsed) {
throw new BuilderException("Each XMLConfigBuilder can only be used once.");
}
parsed = true;
parseConfiguration(parser.evalNode("/configuration"));
return configuration;
}
private void parseConfiguration(XNode root) {
try {
this.propertiesElement(root.evalNode("properties"));
Properties settings = this.settingsAsProperties(root.evalNode("settings"));
this.loadCustomVfs(settings);
this.loadCustomLogImpl(settings);
this.typeAliasesElement(root.evalNode("typeAliases"));
this.pluginElement(root.evalNode("plugins"));
this.objectFactoryElement(root.evalNode("objectFactory"));
this.objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));
this.reflectorFactoryElement(root.evalNode("reflectorFactory"));
this.settingsElement(settings);
this.environmentsElement(root.evalNode("environments"));
this.databaseIdProviderElement(root.evalNode("databaseIdProvider"));
this.typeHandlerElement(root.evalNode("typeHandlers"));
this.mapperElement(root.evalNode("mappers"));
} catch (Exception var3) {
throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + var3, var3);
}
}
SQL语句的执行
Mybatis框架中,我们只提供了mapper接口,框架内部就会帮我们完成剩下的所有工作。这是因为框架内部用到了代理技术,代理对象会自动完成数据的持久化,并返回结果。
Mybatis框架中,insert/delete/update 的操作统一使用update()方法来执行, 而select语句则由query()方法执行,不过最终内部都是使用execute()方法执行,并根据返回的结果再进行不同处理。
缓存
一级缓存:又叫本地缓存,为SqlSession/Statement级别(localCacheScope控制)。默认打开。内部使用的是HashMap.
二级缓存:又叫全局缓存,为Mapper级别。第一次调用mapper下的SQL去查询用户的信息,查询到的信息会存放代该mapper对应的二级缓存区域。 第二次调用namespace下的mapper映射文件中,相同的sql去查询用户信息,会去对应的二级缓存内取结果。默认打开,但需要XML中<cache> 标签配合。【缓存命中率】
在mybatis中,sql语句查询时会先去缓存里面找,如果找到则使用缓存中的数据,否则才会去数据库查找,i查找出来之后顺便放进缓存里面。
mybatis缓存是本地缓存,也就是说可能造成A机器修改了,但是B机器还是用缓存的脏数据问题,因此在分布式/集群项目架构中使用不多。