==========================================================================
Mybatis 一共有两大类Executor 执行器; 第一类就是cache 内存执行器 还有一类就是普通执行器 Executor
从上图我们可以得知 普通Executor 分为三种 一种是SimpleExecutor 一种是ResuseExecutor 还有一种是BatchExecutor
-
SimpleExecutor:每执行一次update或select,就开启一个 Statement对象,用完立刻关闭Statement对象
-
ReuseExecutor:执行update或select,以sql作为key查找 Statement对象,存在就使用,不存在就创建,用完后,不关闭Statement 对象,而是放置于Map<String, Statement>内,供下一次使用。简言之, 就是重复使用Statement对象。
-
BatchExecutor:执行update(没有select,JDBC批处理不支持 select),将所有sql都添加到批处理中(addBatch()),等待统一执行 (executeBatch()),它缓存了多个Statement对象,每个Statement对象 都是addBatch()完毕后,等待逐一执行executeBatch()批处理。与JDBC批 处理相同。
另外一个大类就是cacheExecutor 是缓存执行器:
CacheExecutor其实是封装了普通的Executor,和普通的区别是在查询前先 会查询缓存中是否存在结果,如果存在就使用缓存中的结果,如果不存在还 是使用普通的Executor进行查询,再将查询出来的结果存入缓存。
我们可以通过openSession来确定自己 即将要使用的执行器; 这个在业务当中有很大作用; 现在我们代码使用的就是普通类型的执行器; 这边就不再累赘每个执行器的执行结果;
我们可以从返回对象得知 我们的Mapper对象 是代理对象; 既然有代理对象 那么 就一个有代理工厂 来生成这个代理对象; 我们由此引出2个对象MapperProxy
MapperProxyFactory;
这样就创建出来了代理Mapper; 我们继续往下走;
我们知道代理对象执行方法; 执行到MapperProxy 的 invoke 方法 源码不难; 我们解读一次;
public class MapperProxy implements InvocationHandler, Serializable {
private static final long serialVersionUID = -6424540398559729838L;
private final SqlSession sqlSession;
private final Class mapperInterface;
private final Map<Method, MapperMethod> methodCache;
构造方法
public MapperProxy(SqlSession sqlSession, Class mapperInterface, Map<Method, MapperMethod> methodCache) {
this.sqlSession = sqlSession;
this.mapperInterface = mapperInterface;
this.methodCache = methodCache;
}
执行主要方法;
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
try {
判断是否是一个对象; 如果是一个对象 就直接执行他的方法;
这个方法实际上就是Mapper的三种方式是有关系的;
if (Object.class.equals(method.getDeclaringClass())) {
return method.invoke(this, args);
} else if (isDefaultMethod(method)) {
return invokeDefaultMethod(proxy, method, args);
}
} catch (Throwable t) {
throw ExceptionUtil.unwrapThrowable(t);
}
最后走到这个地方; 引出一个对象 MapoperMethod
final MapperMethod mapperMethod = cachedMapperMethod(method);
return mapperMethod.execute(sqlSession, args);
}
private MapperMethod cachedMapperMethod(Method method) {
MapperMethod mapperMethod = methodCache.get(method);
if (mapperMethod == null) {
mapperMethod = new MapperMethod(mapperInterface, method, sqlSession.getConfiguration());
methodCache.put(method, mapperMethod);
}
return mapperMethod;
}
该对象是sql执行 的一个对象; 该对象带着sql的属性;带着返回值 我们可以从途中可以看出; 最后由mapperMethod.execute 执行
我们可以看出execute 会根据Type去判断 如果是select 就直接进select
这时候 DefaultSqlSession 就会去执行sql; 我们持续往下深挖;最后我们会到BaseExecutor.
这里就会由模板模式去决定调取哪个 Executor
到此 我们Mybatis的全部流程 就讲解完了。
==============================================================
Mybatis 是一个非常适合新手上手源码的框架 非常的简单;
-
SqlSessionFactoryBuilder解析配置文件,包括属性配置、别名配置、 拦截器配置、环境(数据源和事务管理器)、Mapper配置等;解析完这些 配置后会生成一个Configration对象,这个对象中包含了MyBatis需要的所 有配置,然后会用这个Configration对象创建一个SqlSessionFactory对 象,这个对象中包含了Configration对象;
-
拿到SqlSessionFactory对象后,会调用SqlSessionFactory的 openSesison方法,这个方法会创建一个Sql执行器(Executor组件中包含 了Transaction对象),这个Sql执行器会代理你配置的拦截器方法。
-
获得上面的Sql执行器后,会创建一个SqlSession(默认使用 DefaultSqlSession),这个SqlSession中也包含了Configration对象和上面 创建的Executor对象,所以通过SqlSession也能拿到全局配置;
-
获得SqlSession对象后就能执行各种CRUD方法了
以上是获得SqlSession的流程,下面总结下本博客中介绍的Sql的执行流程:
-
调用SqlSession的getMapper方法,获得Mapper接口的动态代理对 象MapperProxy,调用Mapper接口的所有方法都会调用到MapperProxy 的invoke方法(动态代理机制);
-
MapperProxy的invoke方法中唯一做的就是创建一个 MapperMethod对象,然后调用这个对象的execute方法,sqlSession会 作为execute方法的入参;
-
往下,层层调下来会进入Executor组件(如果配置插件会对Executor 进行动态代理)的query方法,这个方法中会创建一个StatementHandler 对象,这个对象中同时会封装ParameterHandler和ResultSetHandler对 象。调用StatementHandler预编译参数以及设置参数值,使用 ParameterHandler来给sql设置参数
Executor组件有两个直接实现类,分别是BaseExecutor和 CachingExecutor。CachingExecutor静态代理了BaseExecutor。Executor 组件封装了Transction组件,Transction组件中又分装了Datasource组件。
- 调用StatementHandler的增删改查方法获得结果,ResultSetHandler 对结果进行封装转换,请求结束。
Executor、StatementHandler 、ParameterHandler、 ResultSetHandler,Mybatis的插件会对上面的四个组件进行动态代理。
-
MapperRegistry:本质上是一个Map,其中的key是Mapper接口的 全限定名,value的MapperProxyFactory;
-
MapperProxyFactory:这个类是MapperRegistry中存的value值, 在通过sqlSession获取Mapper时,其实先获取到的是这个工厂,然后通过 这个工厂创建Mapper的动态代理类;
-
MapperProxy:实现了InvocationHandler接口,Mapper的动态代理 接口方法的调用都会到达这个类的invoke方法;
-
MapperMethod:判断你当前执行的方式是增删改查哪一种,并通过 SqlSession执行相应的操作;
总结
以上是字节二面的一些问题,面完之后其实挺后悔的,没有提前把各个知识点都复习到位。现在重新好好复习手上的面试大全资料(含JAVA、MySQL、算法、Redis、JVM、架构、中间件、RabbitMQ、设计模式、Spring等),现在起闭关修炼半个月,争取早日上岸!!!
下面给大家分享下我的面试大全资料
- 第一份是我的后端JAVA面试大全
后端JAVA面试大全
- 第二份是MySQL+Redis学习笔记+算法+JVM+JAVA核心知识整理
MySQL+Redis学习笔记算法+JVM+JAVA核心知识整理
- 第三份是Spring全家桶资料
MySQL+Redis学习笔记算法+JVM+JAVA核心知识整理
21194100175)]
后端JAVA面试大全
- 第二份是MySQL+Redis学习笔记+算法+JVM+JAVA核心知识整理
[外链图片转存中…(img-9IyFGxV0-1721194100176)]
MySQL+Redis学习笔记算法+JVM+JAVA核心知识整理
- 第三份是Spring全家桶资料
[外链图片转存中…(img-3FLSoGYR-1721194100176)]
MySQL+Redis学习笔记算法+JVM+JAVA核心知识整理