点一下关注吧!!!非常感谢!!持续更新!!!
大数据篇正在更新!https://blog.csdn.net/w776341482/category_12713819.html
# 目前已经更新到了:
- MyBatis(正在更新)
架构设计
把 MyBatis 的功能架构分为三层:
- API 接口层:提供给外部使用的接口 API,开发人员通过这些本地 API 来操作数据库,接口层收到调用请求就会调用数据处理层来完成具体的数据处理。(MyBatis 与数据库的交互有两种方法,通过 MyBatis 的 API、通过 Mapper 代理的方式)
- 数据处理层:负责具体的 SQL 查找、SQL 解析、SQL 执行和执行结果映射处理等。它主要的目的是根据调用请求完成一次数据库的操作。
- 基础支撑层:负责最基础的功能支撑,包括连接管理、事务管理、配置加载和缓存处理,这些都是共用的东西,将他们抽取出来作为最基础的组件。为上层的数据处理层提供最基础的支撑。
主要构件
层次结构
总体流程
加载配置初始化
触发条件:加载配置文件
配置来源于两个地方,一个是配置文件(主配置文件 config.xml、mapper.xml),一个是 Java 代码中的注解,将主配置内容解析封装到 Configuration,将 SQL 的配置信息加载为一个 mappedstatement 对象,存储在内存之中。
接受调用请求
- 触发条件:调用 MyBatis 的 API
- 传入参数:为 SQL 的 ID 和传入参数对象
- 处理过程:将请求传递给下层的请求处理层进行处理
处理操作请求
触发条件:API 接口层传递请求过来
传入参数:为 SQL 的 ID 和传入参数对象
处理过程:
- 根据 SQL 的 ID 查找对应的 MappedStatement 对象
- 根据传入参数对象解析 MappedStatement 对象,得到最终要执行的 SQL 和执行传入的对象
- 获取数据库连接,根据得到的最终 SQL 语句和执行传入参数到数据库进行执行,并得到结果。
- 根据 MappedStatement 对象中的结果映射配置对得到的执行结果进行转换处理,并得到最终的处理结果。
- 释放连接资源
- 返回处理结果
源码剖析
初始化
java
Inputstream inputstream = Resources.getResourceAsStream("mybatis-config.xml");
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream);
初始化的 build 方法中,如下:
java
// 1. 最初调用的 build 方法
public SqlSessionFactory build(InputStream inputStream) {
// 调用了重载方法,传入默认的环境和属性
return build(inputStream, null, null);
}
// 2. 重载的 build 方法
public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {
try {
// XMLConfigBuilder 负责解析 MyBatis 的配置文件
XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
// 解析配置文件并返回 Configuration 对象,再调用重载的 build 方法
return build(parser.parse());
} catch (Exception e) {
// 异常处理:将异常包装成一个运行时异常并抛出
throw ExceptionFactory.wrapException("Error building SqlSession.", e);
}
}
MyBatis 在初始化的时候,会将 MyBatis的配置信息全部加载到内存中,使用 org.apache.ibatis.session.Configuration 实例来维护。
java
/**
* 解析 XML 配置并转换为 Configuration 对象。
*/
public Configuration parse() {
// 如果已解析,抛出 BuilderException 异常
if (parsed) {
throw new BuilderException("Each XMLConfigBuilder can only be used once.");
}
// 标记为已解析
parsed = true;
// 解析 XML 配置根节点
parseConfiguration(parser.evalNode("/configuration"));
return configuration;
}
/**
* 解析 XML 配置节点并逐一处理各个标签。
*/
private void parseConfiguration(XNode root) {
try {
// 按顺序解析各个 XML 配置部分
// 1. 解析 <properties /> 标签
propertiesElement(root.evalNode("properties"));
// 2. 解析 <settings /> 标签并转换为 Properties 对象
Properties settings = settingsAsProperties(root.evalNode("settings"));
// 3. 加载自定义 VFS 实现类
loadCustomVfs(settings);
// 4. 解析 <typeAliases /> 标签
typeAliasesElement(root.evalNode("typeAliases"));
// 5. 解析 <plugins /> 标签
pluginElement(root.evalNode("plugins"));
// 6. 解析 <objectFactory /> 标签
objectFactoryElement(root.evalNode("objectFactory"));
// 7. 解析 <objectWrapperFactory /> 标签
objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));
// 8. 解析 <reflectorFactory /> 标签
reflectorFactoryElement(root.evalNode("reflectorFactory"));
// 9. 将解析得到的 settings 配置赋值给 Configuration 对象
settingsElement(settings);
// 10. 解析 <environments /> 标签
environmentsElement(root.evalNode("environments"));
// 11. 解析 <databaseIdProvider /> 标签
databaseldProviderElement(root.evalNode("databaseldProvider"));
// 12. 解析 <typeHandlers /> 标签
typeHandlerElement(root.evalNode("typeHandlers"));
// 13. 解析 <mappers /> 标签
mapperElement(root.evalNode("mappers"));
} catch (Exception e) {
// 捕获解析过程中可能出现的异常并抛出自定义异常
throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + e, e);
}
}
介绍一下 MappedStatement:MappedStatement 与 Mapper 配置文件中的一个select/update/insert/delete 节点相对应。
mapper 中配置的标签都被封装到了此对象中,主要用途是描述一条 SQL 语句。
刚开始介绍配置文件的过程中,会对 mybatis-config.xml 中的各个标签都进行解析,其中有 mappers 标签用引入 mapper.xml 文件或者配置 mapper 接口目录。
xml
<select id="getUser" resultType="user" >
select * from user where id=#{id}
</select>
一个 Select 标签会在初始化配置文件时,被解析封装成一个 MappedStatement 对象,然后存储在 Configuration 对象的 MappedStatements 属性中,它是一个 HashMap,存储时 key=全限定类名+方法名,value=MappedStatement 对象。
在 XMLConfigBuilder 中的处理:
java
private void parseConfiguration(XNode root) {
try {
// 省略其他标签的处理
mapperElement(root.evalNode("mappers"));
} catch (Exception e) {
throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + e, e);
}
}
到此 XML 配置文件的解析就结束了,回到步骤 2 中调用重载的 build 方法。
java
public SqlSessionFactory build(Configuration config) {
// 创建了 DefaultSqlSessionFactory 对象
return new DefaultSqlSessionFactory(config);
}
SqlSession
先简单介绍 SqlSession,SqlSession 是一个接口,它有两个实现类:
- DefaultSqlSession
- SqlSessionManager
SqlSession 是 MyBatis 中用于和数据库交互的顶层类,通常将它与 ThreadLocal 绑定,一个回话使用一个 SqlSession,结束之后需要进行 close。
java
public class DefaultSqlSession implements SqlSession {
private final Configuration configuration;
private final Executor executor;
// 省略
}
SqlSession 中最重要的参数:
- Configuration 与初始化的时候相同
- Executor 为执行器
Executor
Executor 也是一个接口,有三个常用实现类:
- BatchExecutor 重用语句并执行批量更新
- ReuseExecutor 重用预处理语句 prepared statments
- SimpleExecutor 普通的执行器(默认的)
当我们获取到 SqlSession 的时候:
java
// 6. 进入 openSession 方法。
public SqlSession openSession() {
// getDefaultExecutorType() 传递的是 SimpleExecutor
// 通过 openSessionFromDataSource 方法创建 SqlSession
return openSessionFromDataSource(configuration.getDefaultExecutorType(), null, false);
}
// 7. 进入 openSessionFromDataSource 方法。
// ExecutorType 为 Executor 的类型,TransactionIsolationLevel 为事务隔离级别,autoCommit 是否开启事务
// openSession 的多个重载方法可以指定获得的 SqlSession 的 Executor 类型和事务的处理
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);
// 根据指定的 Executor 类型和事务创建 Executor
final Executor executor = configuration.newExecutor(tx, execType);
// 返回一个 DefaultSqlSession 对象,传入配置、executor 和 autoCommit 状态
return new DefaultSqlSession(configuration, executor, autoCommit);
} catch (Exception e) {
// 捕获异常,关闭事务,可能已经获取了数据库连接,因此需要关闭
closeTransaction(tx);
// 重新抛出异常,或处理异常逻辑
throw new RuntimeException("Error occurred while opening session", e);
}
}
后续可跟进 query 方法,最后会创建一个 StatementHandler 对象,然后将必要的参数传递给 StatementHandler,使用 StatementHandler 来完成对数据库的查询,最终返回 List 结果集。
从上面的代码中我们可以看出,Executor 的功能和作用是:
- 根据传递的参数,完成 SQL 的动态解析,生成 Bound SQL 对象,供 StatementHandler 使用
- 为查询创建缓存,来提高性能
- 创建 JDBC 的 Statement 连接对象,传递给 StatementHandler 对象,返回 List 查询对象。
StatementHandler
StatementHandler 对象主要完成了两个工作:
- 对于 JDBC 的 PreparedStatement 类型的对象,创建的过程中,我们使用的是 SQL 语句字符串会包含若干个占位符,StatementHandler 通过 parameter(statement)方法对 Statement 进行设值
- StatementHandler 通过 List query 方法来完成执行 Statement,将 Statement 对象返回的 resultSet 封装成 List
进入到 StatementHandler 的 parameterize 方法的实现:
java
public void parameterize(Statement statement) throws SQLException {
parameterHandler.setParameters((PreparedStatement) statement);
}