MyBatis 原理浅析 3——数据操作
来源:互联网 发布:女狙击手知乎 编辑:程序博客网 时间:2024/06/10 06:21
前言
在前文《MyBatis 原理浅析——基本原理》一文中简单分析了 MyBatis 的实现原理,MyBatis 的数据库操作是通过 Executor 执行的。Executor 是一个接口,有三个实现类,分别是 SimpleExecutor、ReuseExecutor 和 BatchExecutor。
查询数据的流程
查询数据是通过 SqlSession 的方法实现的,SqlSession 封装了 Executor 的相关操作。以 select 为例,首先根据 SQL 语句关联的 statement 从 configuration 中获取 MappedStatement 对象,然后调用 Executor 的 query 方法执行查询操作。statement 的格式是命名空间+ID,ID 即是 XML 中 select 标签的 id 属性。MappedStatement 对象存储了 XML 中的 SQL 配置,如 ParameterMap、ResultMap 等。
@Override
public void select(String statement, Object parameter, RowBounds rowBounds, ResultHandler handler) {
try {
MappedStatement ms = configuration.getMappedStatement(statement);
executor.query(ms, wrapCollection(parameter), rowBounds, handler);
} catch (Exception e) {
throw ExceptionFactory.wrapException("Error querying database. Cause: " + e, e);
} finally {
ErrorContext.instance().reset();
}
}
默认情况下,使用 Executor 接口的 SimpleExecutor 实现。SimpleExecutor 继承了抽象类 BaseExecutor。BaseExecutor 实现了 Executor 接口的方法,实现了缓存机制,可以从缓存中直接返回查询结果,但更具体的数据库操作交给子类 SimpleExecutor 实现。在 SimpleExecutor 类中执行查询的 doQuery 方法如下所示。首先从 Configuration 中创建 StatementHandler 接口实例,默认使用 RoutingStatementHandler 实现。然后在 prepareStatement 方法中获取数据库连接、初始化 Statement、设置参数等。再调用 StatementHandler 的 query 方法,执行数据查询,查询结果交给 resultHandler 处理。最后关闭 Statement。
@Override
public <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
Statement stmt = null;
try {
Configuration configuration = ms.getConfiguration();
StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql);
stmt = prepareStatement(handler, ms.getStatementLog());
return handler.<E>query(stmt, resultHandler);
} finally {
closeStatement(stmt);
}
}
在 RoutingStatementHandler 中会根据配置选择一个 StatementHandler 的实现用于进一步的数据处理,默认是 PreparedStatementHandler 类。在该类的 query 方法中会执行 Statement 数据查询请求,请求完成后调用 ResultSetHandler 对查询结果进行处理和封装。ResultSetHandler 接口定义了对返回结果集进行处理的方法,默认使用的实现类是 DefaultResultSetHandler,在 handleResultSets 方法中完成结果集到 Java Bean 的映射。
@Override
public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {
PreparedStatement ps = (PreparedStatement) statement;
ps.execute();
return resultSetHandler.<E> handleResultSets(ps);
}
查询结果的缓存
MyBatis 支持对查询结果进行缓存,以减少数据库操作提高效率,默认情况下执行 insert、update、delete 等操作会清理缓存。执行查询操作前,首先创建 CacheKey 对象,根据 SQL 语句、id、offset、limit 和参数更新 CacheKey 对象,CacheKey 对象会记录这些数据并更新 hashcode、checksum、count 几个整数,这些数据都用于判断 CacheKey 对象是否相等。
public void update(Object object) {
int baseHashCode = object == null ? 1 : ArrayUtil.hashCode(object);
count++;
checksum += baseHashCode;
baseHashCode *= count;
hashcode = multiplier * hashcode + baseHashCode;
updateList.add(object);
}
select 语句的查询结果以 Map 形式存放在 PerpetualCache 类中,Map 的 key 是 CacheKey 对象,Map 的 value 是查询结果。
更新数据的流程
DefaultSqlSession 的 insert、delete 操作都是复用 update 操作实现的,update 的操作流程与 select 类似,不做过多阐述。所不同的是,执行 update 操作前需要先清理缓存,在 update 操作完成以后,还需要返回受影响的行数和 KeyGenerator 配置的自增值。
事务提交与回滚
DefaultSqlSession 的 commit 和 rollback 操作都是在 BaseExecutor 中实现的,先清除缓存,然后清理 Statement,如果有需要再调用 Transaction 的相关方法。如果要求强制执行,或者不自动提交且有脏数据,就会执行 Transaction 的 commit 或 rollback 操作。
每周 3 篇学习笔记或技术总结,面向有一定基础的 Java 程序员,内容涉及 Java 进阶、虚拟机、MySQL、NoSQL、分布式计算、开源框架等多个领域。关注作者第一时间获取最新内容。
相关阅读:
MyBatis 原理浅析 2——配置解析
- MyBatis 原理浅析 3——数据操作
- 浅析mybatis原理
- MyBatis原理--插入操作
- MyBatis原理--查询操作
- MyBatis总结之框架原理浅析
- Mybatis源码浅析、定制原理及方法
- Mybatis数据操作
- Mybatis数据操作
- 浅析Oracle数据恢复操作
- 浅析正则表达式—(原理篇)
- 浅析正则表达式—(原理篇)
- 数据结构 — 浅析红黑树原理以及实现
- 【Mybatis】——CRUD操作
- MyBatis——关联操作
- mybatis批量操作Oracle数据
- Mybatis-浅析
- Mybatis 浅析
- mybatis——【持久化框架】Mybatis简介与原理
- 【java基础】String、StringBuilder和StringBuffer的区别
- LabVIEW自带函数实现SQL Server操作(下)
- linux安装mysql数据库
- 关于 Android studio的Gradle 那些坑
- MySQL优化实例
- MyBatis 原理浅析 3——数据操作
- String、StringBuffer与StringBuilder之间区别
- 凸优化学习笔记(三)之凸集基本概念
- WSN之串口
- iOS 安卓 服务器后台 公用的简单加密和解密
- MovieLens 《用Python进行数据分析》
- 【JavaWeb-30】SpringMVC原理、入门程序、参数传递
- 自定义VideoView实现视频画面的缩放
- 'getDrawable(int)' is deprecated,getDrawable过时