Java进阶笔记(二):Mybatis相关
1.Mybatis动态sql作用
Mybatis动态sql可以灵活的根据某种条件拼接出需要的SQL语句,便于编写通用的SQL语句。
2.有哪些动态sql
<where>:可以代替SQL中的where,只会在子元素返回任何内容的情况下才插入 WHERE 子句。而且,若子句的开头为 AND 或 OR,where 元素也会将它们去除。
<if>:根据标签中的属性test指定的判断条件,满足条件则拼接其中的SQL语句,否则不拼接。
<foreach>:用来对集合进行遍历,一般与SQL语句where...in连用,查询符合条件的结果。
<choose><when><otherwise>:与Java中的switch类似,从多个条件中选一个执行拼接。
<set>:可以代替SQL中的set,可以动态配置set关键字,和剔除追加到条件末尾的任何不相关的逗号。
<sql><include>:使用sql标签抽出可以公用的SQL语句,使用include标签使用公用的SQL语句。
<trim>:可以完成set或者是where标签的功能。
<bind>:可以使用 OGNL 表达式创建一个变量并将其绑定到上下文中,可以避免因更换数据库而修改 SQL,也能预防 SQL 注入。
3.动态sql的执行原理
动态SQL的执行原理:动态SQL一般与普通SQL语句一起使用,位于xml文件中,或者使用注解的方式写在java文件中;当mybatis准备执行SQL时,会加载这些文件中对应的部分,获得普通SQL与动态SQL;如果发现动态SQL,则进行相应的特殊处理解析,最终生成可执行的SQL语句。
4.Mybatis是否支持延迟加载
Mybatis 仅支持 association 关联对象和 collection 关联集合对象的延迟加载,association 指的就是一对一,collection 指的就是一对多查询。在 Mybatis配置文件中,可以配置是否启用延迟加载 lazyLoadingEnabled=true|false。
5.Mybatis延迟加载的实现原理
使用 CGLIB 创建目标对象的代理对象,当调用目标方法时,进入拦截器方法,
将关联查询多张表的操作改为按顺序查询单张表的操作。
6.Mybatis的Executor执行器及区别
有3个执行器:
SimpleExecutor:每执行一次update或select,就开启一个Statement对象,用完立刻关闭Statement对象。
ReuseExecutor:执行update或select,以sql作为key查找Statement对象,存在就使用,不存在就创建,用完后,不关闭Statement对象,而是放置于Map内,供下一次使用。简言之,就是重复使用Statement对象。
BatchExecutor:执行update(没有select,JDBC批处理不支持select),将所有sql都添加到批处理中(addBatch()),等待统一执行(executeBatch()),它缓存了多个Statement对象,每个Statement对象都是addBatch();完毕后,等待逐一执行executeBatch()批处理。与JDBC批处理相同。
7.简述Mybatis的一级、二级缓存
一级缓存的存储结构是HashMap;
范围是SqlSession;
失效场景:只要SqlSession执行commit操作(不需要执行增删改查,已找到源码并测试),就会将这个SqlSession的一级缓存全部清空。
二级缓存的存储结构是HashMap;
范围是Mapper;
失效场景:开启二级缓存后,只有执行对应mapper的增删改操作并执行commit后,才会清空该mapper的整个二级缓存,只执行commit是不会清空的(已测试);
开启二级缓存后,执行select后,需要执行commit(或者close)方法,才会将查询结果提交给二级缓存,其它SqlSession查询时才能从二级缓存获取值;如果不执行commit(或close),则二级缓存没有数据。
8.Mybatis插件的运行原理
Mybatis支持给执行器Executor、SQL语法构建器StatementHandler、参数处理器ParameterHandler、结果集处理器ResultSetHandler这四大对象添加插件;当需要使用这些对象执行方法时,Mybatis会使用这些对象的代理对象,而代理对象已经在初始化时就添加了插件对象,因此具有插件的功能与原本的功能;代理对象执行方法时,就相当于执行了插件的方法与原对象本应该执行的方法。原理是AOP(面向切面)。
9.编写Mybatis插件的方法
(1) 新建一个自定义类作为插件类,实现Interceptor接口;
(2) 在这个类中使用@Signature注解指明要给哪个类的哪个方法加插件,也要写清楚那个方法的参数是什么;
(3) 在这个类中重写intercept方法做为插件方法;
(4) 在这个类中重写plugin方法,将这个插件(拦截器)添加到链中;
(5) 在这个类中重写setProperties方法,可以获取到一些配置参数;
(6) 在配置文件(例如sqlMapConfig.xml)中,添加<plugins>与<plugin>标签,注册插件;
(7) 编写测试类,查看插件是否生效。