Mybatis动态sql是做什么的?都有哪些动态sql?简述一下动态sql的执行原理
动态sql的用途
Mybatis动态sql的主要是为使用者提供了可以动态变更sql的能力.也就是可以根据使用者传入的参数来动态拼接sql,以便让sql可以复用.
动态sql的类型
if标签
主要用于添加判断,如果test中的内容为true,则if中的text会添加到sql中
where标签
where标签一般不会单独使用,它的主要作用是为了配合其他的标签来判断是否需要加入where语句,以避免sql语句报错
choose,when,otherwise
这三个标签需要连用,首先由choose标签开启判断,类似于if else的结构
set
类似where标签,是为了在update时动态判断是否需要添加set时的标签
trim
trim是一个比较强大的标签,可以通过前缀,后缀,前缀重写和后缀重写来实现各种语句的拼接,比如上面的set,where标签
foreach
遍历标签,可以遍历传入的参数,配合前缀,后缀以及中间的间隔符,可以实现批量操作.
动态sql的执行原理
- 加载sqlMapConfig.xml文件以获取mapper.xml文件的位置
- 加载mapper.xml文件
- 扫描出各种节点
- 将扫描后的节点在加载过程中调用XMLStatementBuilder的方法来返回SlqSource对象
- 接着在XMLScriptBuilder中调用如下方法来解析动态标签
- 并在这个方法中选择对应的动态标签handler来处理
- 最终返回了一个sqlSource对象.这个对象唯一的方法就是返回boundSql
- 此时使用还是原来的流程来操作boundSql即可.
Mybatis都有哪些Executor执行器?他们之间的区别是什么?
Mybatis主要有以下几个Executor执行器
区别
其实可以见名知意.
- CachingExecutor是BaseExecutor的一个包装.添加了关于二级缓存的相关内容
图中标红的位置就是BaseExecutor的一个实现.
- BaseExecutor是一个基于一级缓存的默认实现父类,对一级缓存机型管理.对于后续调用handler的处理会交给子类来完成
图中标红的位置是一个抽象方法,所以会调用子类的实现
- SimpleExecutor是基本的Executor实现类,默认会使用它.它和ReuseExecutor的最大区别在于Statement是否会重用.
可以看到没有关于Statement的信息
- ReuseExecutor内部缓存了statement,会重用Statement.
可以看到有一个statement的缓存,同时名字也有提到,是一个reuse的作用,所以区别主要在用是否重用Statement.
- BatchExecutor是基于批处理提供的Executor,主要用于批处理的更新和查询
批处理的则和其他的处理器的逻辑完全不一样.
简述一下Mybatis的一级,二级缓存(分别从存储结构,范围,失效条件.三个方面来作答)?
一级缓存
存储结构
如图所示,是使用hashmap的结构来存储缓存的.
范围
一级缓存的范围仅限于SqlSession层级.如下图逻辑所示
- 创建sqlSession
- 创建Executor
3.创建我们的缓存类.并在缓存类初始化时创建hashmap
失效条件
当执行update操作时,会对应的清除一级缓存.
二级缓存
存储结构
可以看到这里默认的二级缓存和一级缓存的结构是一样的,也是hashmap
范围
二级缓存的范围是整个mapper.对于所有的sqlSession是公用的.
如果二级缓存开启会使用CachingExecutor,会取上面创建mapper时创建的缓存使用
失效条件
更新时会判断是否需要清空缓存.如果此时判断需要,则缓存会被清空.
简述Mybatis的插件运行原理,以及如何编写一个插件.
Mybatis有四大对象被允许拦截并创建出代理对象,分别是
- Executor
- StatementHandler
- ParameterHandler
- ResultSetHandler
- Mybatis会获取所有的interceptor,并使用责任链模式来依次调用interceptor的plugin方法.
- 插件实现interceptor并加入责任链中,并在intercept方法中实现自己的invcation.
- 当责任链调用到插件时,需要判断对象是否是我们需要拦截的对象.如果是,则调用plugin的wrap方法,此时会根据你的invocation来动态生成一个代理对象并返回.
- 最终责任链执行完毕后会返回最后的一个代理对象.
如何编写一个插件
- 实现mybatis提供的interceptor接口,并实现对应的方法.
- 在实现类添加类注解,并在代码中判断是否需要生成代理类.
- 将接口全路径配置在sqlMapConfig中,以便获取自定义的插件