Mybatis源码SqlSession源码分析
文章目录
- 前言
- 一、SqlSession
- 二、DefaultSqlSession
- 三、MappedStatement
- 四、Executor
前言
前面简单的写了个mybatis的demo运行,并且根据demo运行了解了mybatis的执行流程,其实mybatis的源码还是很简单的,看过Spring之后就会感觉看其他框架的源码就是福利啊,在mybatis的执行流程中有很多经常听到或者面试被问到的几个类,尤其是SqlSession,本文将对SqlSession的执行进行简单的分析。
一、SqlSession
SqlSession是mybatis中一个非常重要的核心类,它主要用来维持程序与数据库之间的连接以及通信,可以执行对应的mapper方法获取返回结果,相当于JDBC中的Connection。接下来看其源码:
public interface SqlSession extends Closeable {<T> T selectOne(String var1);<T> T selectOne(String var1, Object var2);<E> List<E> selectList(String var1);<E> List<E> selectList(String var1, Object var2);<E> List<E> selectList(String var1, Object var2, RowBounds var3);<K, V> Map<K, V> selectMap(String var1, String var2);<K, V> Map<K, V> selectMap(String var1, Object var2, String var3);<K, V> Map<K, V> selectMap(String var1, Object var2, String var3, RowBounds var4);void select(String var1, Object var2, ResultHandler var3);void select(String var1, ResultHandler var2);void select(String var1, Object var2, RowBounds var3, ResultHandler var4);int insert(String var1);int insert(String var1, Object var2);int update(String var1);int update(String var1, Object var2);int delete(String var1);int delete(String var1, Object var2);void commit();void commit(boolean var1);void rollback();void rollback(boolean var1);List<BatchResult> flushStatements();void close();void clearCache();Configuration getConfiguration();<T> T getMapper(Class<T> var1);Connection getConnection();
}
可以看到SqlSession是一个接口,提供了一些增删改查方法以及事务的操作等方法。SqlSession有两个实现类SqlSessionManager和DefaultSqlSession。
二、DefaultSqlSession
通过打断点可以知道我们示例代码中的SqlSession使用的是DefaultSqlSession。那么我们就对主要对DefaultSqlSession进行一下研究。
我们看一下其源码,源码中有这么几个属性:configuration主要用来存放mybatis-config.xml初始化加载的配置文件中的信息,这里要知道mapper.xml其实也是config中的配置文件,因为这是在config里面配置了扫包引入的;Executor是mybatis中的执行器,是用来执行SQL操作的;autoCommit是自动事务的提交;
这里需要注意的一件事就是我把源码的注释也复制过来了,看这里有一行很重要的信息:这个类不是线程安全的。
/*** The default implementation for {@link SqlSession}.* Note that this class is not Thread-Safe.*/
public class DefaultSqlSession implements SqlSession {private Configuration configuration;private Executor executor;private boolean autoCommit;private boolean dirty;
}
随便找个查询语句来看一下其执行的流程:
public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) {List var5;MappedStatement ms = this.configuration.getMappedStatement(statement);var5 = this.executor.query(ms, this.wrapCollection(parameter), rowBounds, Executor.NO_RESULT_HANDLER);...//省略简化了N多代码return var5;}
首先通过执行的方法(com.mayikt.mapper.UserMapper.getUser)作为参数从配置文件中取出了一个Statement对象,来看一下MappedStatement是干什么的。
三、MappedStatement
public final class MappedStatement {private String resource;private Configuration configuration;private String id;private Integer fetchSize;private Integer timeout;private StatementType statementType;private ResultSetType resultSetType;private SqlSource sqlSource;private Cache cache;private ParameterMap parameterMap;private List<ResultMap> resultMaps;private boolean flushCacheRequired;private boolean useCache;private boolean resultOrdered;private SqlCommandType sqlCommandType;private KeyGenerator keyGenerator;private String[] keyProperties;private String[] keyColumns;private boolean hasNestedResultMaps;private String databaseId;private Log statementLog;private LanguageDriver lang;private String[] resultSets;
}
假装不知道这个类是干什么的,由于源码上面没有注释,我们直接看一下其属性,里面存放有很多熟悉的信息像来源、超时时间、resultType、parameterMap等信息,我们就可以猜测其是mapper.xml的实例化对象,然后看一下断点上面记录的信息,简单截取部分断点信息,通过id就可以判断这是mapper里面的一个方法节点的实例化,因为其很多属性都是单一字符串的例如id等属性,直接指向了其中的一个节点getUser,所以MappedStatement是mapper.xml中一个节点的实例化对象。
继续往下执行代码,执行了executor.query(),咱们继续往下接着看。
四、Executor
Executor是mybatis中的执行器,真正执行SQL操作的,可以看一下这是个接口类,下面有多种实现类:BaseExecutor、SimpleExecutor、BatchExecutor、ReuseExecutor 以及CachingExecutor。看名称就知道BatchExecutor是进行批处理操作的执行器,CachingExecutor是带缓存的执行器,SimpleExecutor是真正干活的执行器,那些都是在其基础上进行了封装。mybatis在没有配置的情况下默认走的CachingExecutor。
看一下CachingExecutor属性,直接断点的截图,可以看到其有两个属性,其中一个执行器用了简单的执行器SimpleExecutor,还有事务的管理器属性。
执行查询操作:
public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException {BoundSql boundSql = ms.getBoundSql(parameterObject);CacheKey key = this.createCacheKey(ms, parameterObject, rowBounds, boundSql);return this.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
}
其中boundSql是从MappedStatement获取的SQL信息,包含SQL语句以及参数等信息。CacheKey是缓存的key,这个要看一下,通过缓存的key就可以知道mybatis中缓存的内容是什么。这个缓存key又是从BaseExecutor中的createCacheKey()方法构建出来的。
public CacheKey createCacheKey(MappedStatement ms, Object parameterObject, RowBounds rowBounds, BoundSql boundSql) {if (this.closed) {throw new ExecutorException("Executor was closed.");} else {CacheKey cacheKey = new CacheKey();//设置ID,其实就是指定的方法com.mayikt.mapper.UserMapper.getUsercacheKey.update(ms.getId());//查询的分页偏移量cacheKey.update(rowBounds.getOffset());cacheKey.update(rowBounds.getLimit());//执行的SQL语句cacheKey.update(boundSql.getSql());List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();TypeHandlerRegistry typeHandlerRegistry = ms.getConfiguration().getTypeHandlerRegistry();//下面又对方法的参数进行了记录for(int i = 0; i < parameterMappings.size(); ++i) {ParameterMapping parameterMapping = (ParameterMapping)parameterMappings.get(i);...cacheKey.update(value);}...return cacheKey;}}
比较简单咱就不看类的源码了,直接断点看一下存放的内容,跟上面的分析结果一样,方法、参数、环境。
然后再进行查询,查询先到缓存中根据缓存的key去查找,最终存放在了PerpetualCache类中,里面有个map的缓存记录,key就是缓存的key,value是对应key查询出来的结果为了演示再写一个重复查询看一下断点,源码比较简单就不往上贴了,看一下结果其实第二次执行的时候直接从缓存里面取出了结果返回的。
再往里执行其实又到了SimpleExecutor去执行,到了这里其实很多人都已经不陌生了,再往下就是JDBC的操作了。
public <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {Statement stmt = null;List var9;try {Configuration configuration = ms.getConfiguration();StatementHandler handler = configuration.newStatementHandler(this.wrapper, ms, parameter, rowBounds, resultHandler, boundSql);stmt = this.prepareStatement(handler, ms.getStatementLog());var9 = handler.query(stmt, resultHandler);} finally {this.closeStatement(stmt);}return var9;}
Mybatis源码SqlSession源码分析相关推荐
- 【Mybatis源码】源码分析
[Mybatis源码]源码分析 (一)Mybatis重要组件 [1]四大核心组件 (1)SqlSessionFactoryBuilder (2)SqlSessionFactory (3)SqlSess ...
- Colly源码解析——结合例子分析底层实现
通过<Colly源码解析--框架>分析,我们可以知道Colly执行的主要流程.本文将结合http://go-colly.org上的例子分析一些高级设置的底层实现.(转载请指明出于break ...
- java 头尾 队列_源码|jdk源码之栈、队列及ArrayDeque分析
栈.队列.双端队列都是非常经典的数据结构.和链表.数组不同,这三种数据结构的抽象层次更高.它只描述了数据结构有哪些行为,而并不关心数据结构内部用何种思路.方式去组织. 本篇博文重点关注这三种数据结构在 ...
- yocto源码下载和目录分析
文章目录 前言 一.搭建环境 电脑硬件要求 安装依赖 repo 什么是repo? 获取repo 设置git 二.获取yocto源码 三.yocto源码目录讲解 总结 前言 本文记录下载yocto的源码 ...
- openxr runtime Monado 源码解析 源码分析:CreateInstance流程(设备系统和合成器系统)Compositor comp_main client compositor
monado系列文章索引汇总: openxr runtime Monado 源码解析 源码分析:源码编译 准备工作说明 hello_xr解读 openxr runtime Monado 源码解析 源码 ...
- openxr runtime Monado 源码解析 源码分析:CreateSwapchain 画布 HardwareBuffer共享纹理 渲染线程 xrEndeFrame comp_renderer
monado系列文章索引汇总: openxr runtime Monado 源码解析 源码分析:源码编译 准备工作说明 hello_xr解读 openxr runtime Monado 源码解析 源码 ...
- 【Android源码】源码分析深度好文+精编内核解析分享
阅读Android源码的好处有很多,比如:可以加深我们对系统的了解:可以参考牛人优雅的代码实现:可以从根本上找出一些bug的原因-我们应该庆幸Android是开源的,所有的功能都可以看到实现,所有的b ...
- lodash源码中debounce函数分析
lodash源码中debounce函数分析 一.使用 在lodash中我们可以使用debounce函数来进行防抖和截流,之前我并未仔细注意过,但是不可思议的是,lodash中的防抖节流函数是一个函数两 ...
- 【spring源码】源码分析
[spring源码]源码分析 (一)mac版idea引入spring源码 (二)spring的学习流程 (三)spring源码分析 [1]refresh()方法概览(AbstractApplicati ...
- Linux内核学习(五):linux kernel源码结构以及makefile分析
Linux内核学习(五):linux kernel源码结构以及makefile分析 前面我们知道了linux内核镜像的生成.加载以及加载工具uboot. 这里我们来看看linux内核的源码的宏观东西, ...
最新文章
- [c++] vector<vector<int>>排序
- Interface继承至System.Object?
- FLV封装格式分析器
- JavaSE各阶段练习题----集合-Collection-Set-List
- java异常类层次结构图
- 触发死锁怎么办?MySQL 的死锁系列:锁的类型以及加锁原理了解一下!
- Android Bitmap(位图)详解
- Leetcode - Permutations I,II
- 特征提取、特征描述、特征匹配的通俗解释
- 反向传播网络(BP 网络)
- RubyOnRails with Ajax
- python+django+mysql图书馆座位预约系统毕业设计毕设开题报告
- 洛谷再分肥宅水c语言,【菜鸟进阶之路】P5706【深基2.例8】再分肥宅水 - 洛谷
- harbor1.9.1搭建
- Docker —— 从入门到实践
- 股票基本名词,你知道多少?
- 国仁网络资讯:微信视频号怎么变现赚钱;首先要了解平台的底层逻辑与算法原理。
- 回归预测 | MATLAB实现PSO-LSSVM粒子群算法优化最小二乘支持向量机多输入单输出
- matlab/6-sps并联机构运动学位置反解
- html点赞代码java_17种 HTML5字体图标点赞动画特效源码