1. Mapper在spring管理下其实是单例,为什么可以是一个单例?
- 首先,mapper 内部不包含 成员字段,无状态单例是安全的
- 另外,一直存在不用每次调用都new 一个新实例
2. MyBatis在Spring集成下没有mapper的xml文件会不会报错,为什么?
- 不会报错,因为支持 xml 和 annotation 两种
3. TypeHandler手写
- 继承自 BaseTypeHandler
-
public class ExampleTypeHandler extends BaseTypeHandler<Date>
- 配置到configuration 里面
- 具体使用
- 比如 String 和Date 之间的互转
4. 手写Plugin,多个interceptor到底谁先执行?顺序由谁决定的?
- 允许使用插件拦截的接口
- 根据签名判断其拦截点,根据jdbc 执行顺序,执行到相应的点,进行执行
- 配置到 configuration 里面
1.怎么验证一级缓存的存在?
- 相同的查询,连续查询两遍,记录查询用时,会发现第二次快得多
- update、 insert、delete 等语句会触发清除缓存
- 一级缓存默认开启,SqlSession 级别的
- 二级缓存默认关闭,SqlSessionFactory 级别的
二级缓存是需要配置来开启的:
- 所以,一级缓存,在存在俩sqlsession 时,可能存在脏数据的情况
- 比如,sqlsessionA 两次相同查询t 表中间,sqlsessionB 更新了t表数据,第二次查询的数据就是可能已被修改的脏数据
2.验证N+1问题
- 所谓级联查询(嵌套查询)
- 外层查询的一条结果数据,由内层查询获得
- 外层查询一次,获得结果数N ,就要进行N 次内层查询(官方不鼓励使用,这样产生大量1+N次查询)
由于1+N 问题的性能损耗,可以考虑配合使用 延时加载
- 配置到 configuration 里面
1、TestMapper 作者为什么要设计这样的形式来做?为什么不是一个class而是一个interface?
- 首先使用 interface 接口已经可以满足,根据全限定名+方法名找到对应的SQL语句,然后MapperProxy代理实现具体的执行
- 所有的执行套路都是一样的,xml文件里面配置也很清楚了,不需要class
- 保留interface 的原因是用户使用方便
2.org.apache.ibatis.executor.BaseExecutor#queryFromDatabase 322行这行代码的意义
- 322行这行代码的意义是声明一个占位符,当发送一次查询数据的请求时,设置该占位符 告诉其他请求 正在查询数据库,请其他请求先阻塞或休眠。
- 当这次请求查询到数据之后,将真正的数据放到占位符的位置,缓存数据。如果其他请求与该次请求查询的数据时一样的,直接从缓存中拿数据减少了查询请求对数据库的压力
3.MyBatis的plugin实现机制
- interceptorChain.pluginAll(executor) 在configuration 内部注册所有的 plugin
- 本质就是getSignatureMap 方法,扫描所有注解,对配置的Signature 方法进行 动态代理
- 代理类就是public class Plugin implements InvocationHandler
- 执行Plugin 的invoke 会判断该方法是否被代理(signatureMap 里面有没有)
- 如果有执行 intercept 方法
- 该方法最后一行执行的proceed 方法,其实就是该方法的invoke 执行
4.lazy loading 是怎么做到的?
- 懒加载在级联查询时用到了,SimpleStatementHandler 里面query结果
- DefaultResultSetHandler 处理结果
- handleResultSets -->handleResultSets -->...getRowValue-->createResultObject
- 如果有嵌套查询且开启了懒加载 那么会使用代理工厂来处理(代理工厂类型cglib或javasissit类型(默认))
- 针对某一个属性,当执行
- protected Set<String> lazyLoadTriggerMethods = new HashSet<String>(Arrays.asList(new String[] { "equals", "clone", "hashCode", "toString" }));
- 在嵌套查询的时候 get/set 方法会触发 ResultLoaderMap LoadPair load() 方法去查询(我看源代码的理解),我找到了触发函数lazyLoadTriggerMethods 里面没有get/is 依赖的是PropertyNamer.isGetter(methodName)