1:各个包的含义
1.1:annotations mybatis中存在两种类型的MapperStatement加载方式,其中一种是基于xml文件进行的,另外一种是基于java代码的注解方式进行的,这个包里面就是存放了所有的基于java代码的注解形式用到的注解。 1.2:binding 在获取到SqlSession之后,可以通过Mapper.class的方式,这个时候会通过MapperRegistry拿到这个class的一个代理MapperProxy,然后在执行这个class对应的方法的时候会被代理执行。 1.3:builder 这个包里面放的时候解析构建,其中MapperAnnotationBuilder负责mapper接口的加载,XMLConfigBuilder是整个mybatis的核心接口,负责加载Configuration,XMLMapperBuilder则负责加载.xml文件类型的mapper 1.4:cache 这个包里面放了缓存相关的实现,最基础的是PerpetualCache这个类实现了Cache接口,在decorators下面的类,则是通过装饰者模式,对PerpetualCache进行的装饰 1.5:cursor 这里面是游标相关的内容 1.6:DataSource 这里面放的是数据源相关的东西,其中包含池化的数据源跟未池化的数据源 1.7:exceptions 里面放的是异常相关类 1.8:executor 这里面是执行sql相关部分, 核心的Executor接口,三个类型SIMPLE、REUSE、BATCH对应三个executor,还有一个CachingExecutor,这个是在允许缓存的时候,进行缓存相关的处理的,如果允许缓存的话,那么就在创建executor的时候,会将目标的executor进行包装一层caching,同时会在创建的时候对插件进行包装 1.9:io 这个是io相关处理用到的包 1.10:jdbc 这个是sql相关的测试辅助类 1.11:lang 1.12:logging 日志相关 1.13: mapping 一个核心类MappedStatement,这个映射后的声明,在mybatis加载的时候会加载所有的.xml中的方法,从而生成MappedStatement。 1.14:parsing 这个里面是解析参数的。 1.15:plugin 这个是插件相关的 1.16:reflection 这个是反射相关的实现 1.17:scripting 1.18:session 一个核心类Configuration,这个是mybatis的全局配置,以及提供给外部调用的接口,外部可以通过操作SqlSession这个接口来完成对数据库的操作。 1.19:transaction 事务相关处理 1.20:type 处理java的参数为jdbc参数,处理jdbc参数为java类型
2:核心流程图
3:一些问题
3.1:#{}和${}的区别是什么? #{}是预编译处理,${}是字符串替换。 Mybatis 在处理#{}时,会将 sql 中的#{}替换为?号,调用 PreparedStatement 的 set 方法来赋值; Mybatis 在处理
时
,
就
是
把
{}时,就是把
时,就是把{}替换成变量的值。使 用#{}可以有效的防止 SQL 注入,提高系统安全性。
3.2:当实体类中的属性名和表中的字段名不一样 ,怎么办 ? 第 1 种: 通过在查询的 sql 语句中定义字段名的别名,让字段名的别名和实体类的属性名一致。 第 2 种: 通过来映射字段名和实体类属性名的一一对应的关系。
3.3:通常一个 Xml 映射文件,都会写一个 Dao 接口与之对应,这个的工作原理是什么?
在加载全局的Configuration中关于mapper相关的时候,会将这个包下面的mapper进行加载,如果是以mapper resource形式加载mapper的时候,在加载完成xml之后会根据这个xml的namespace同时查询是否有对应的class类,如果有的话,那么就会同时加载这个class,然后给这个class创建一个MapperProxyFactory,后续可以在Configuration的getMapper方法的时候可以通过MapperProxyFactory获取到这个mapper接口的MapperProxy,后续所有的方法都会被代理执行。 如果是mapper url形式加载的xml也是一样,会同时加载存在的mapper class。 如果是mapper class的话 那么相反,先加载mapper class 然后加载对应的xml文件。 如果是package name的话 那么就会加载这个package下面的所有的接口。同时如果存在对应的xml的话 也会加载进去。
3.4:Dao 接口里的方法,参数不同时,方法能重载吗? dao接口中的接口全限名就是namespace,而接口全限名+方法名称就是statementId,当调用接口方法时,接口全限名+方法名拼接字 符串作为 key 值,可唯一定位一个 MapperStatement,而mapper class的statementId的规则就是接口class的全路径加上方法名称,所以不能重载。
3.5:Mybatis 是如何进行分页的?分页插件的原理是什么? mybatis支持一RowBounds的形式进行分页,它是针对 ResultSet 结果集执行的内存分页,而非物理分页。这种内存方式的分页对内存有很大的要求。 另一个物理分页的话,就是通过mybatis的插件进行重写sql,在实际执行sql的时候将原先的sql加上对应的数据库类型的方言,然后进行物理分页。
3.6:Mybatis 的 Xml 映射文件中,不同的 Xml 映射文件,id 是否可 以重复? 如果不同的xml并且xml的namespace是不同的,那么是可以重复的,否则是不能重复的。
3.7:一对一、一对多的关联查询 ? 通过association设置一对一关联查询,通过collection设置一对多关联查询。
3.8:Mybatis 是否支持延迟加载?如果支持,它的实现原理是什么? 支持延迟加载,可以通过设置lazyLoadingEnabled来实现,再就是aggressiveLazyLoading配置,这个配置是设置加载的时机的,是在任意一个方法调用的时候进行加载,还是真正配置了关联查询的方法的时候进行关联查询,lazyLoadTriggerMethods配置则是配置哪些方法不触发延迟加载。 实现原理:使用 CGLIB 创建目标对象的代理对象,当调用目标方法时,进入拦截器方法,比如调用 a.getB().getName(),拦截器 invoke()方法发现 a.getB()是 null 值,那么就会单独发送事先保存好的查询关联 B 对象的 sql,把 B 查询上来,然后调用 a.setB(b),于是 a 的对象 b 属性就有值 了,接着完成 a.getB().getName()方法的调用。这就是延迟加载的基本原理。
3.9:Mybatis 的一级、二级缓存 1)一级缓存: 基于 PerpetualCache 的 HashMap 本地缓存,其存储作用域为 Session,当 Session flush 或 close 之后,该 Session 中的所有 Cache 就 将清空,默认打开一级缓存。 2)二级缓存与一级缓存其机制相同,默认也是采用 PerpetualCache,HashMap 存储,不同在于其存储作用域为 Mapper(Namespace),并且可自定义存储源, 如 Ehcache。默认不打开二级缓存,要开启二级缓存,使用二级缓存属性类需 要实现 Serializable 序列化接口(可用来保存对象的状态),可在它的映射文件 中配置 ; 3)对于缓存数据更新机制,当某一个作用域(一级缓存 Session/二级缓存 Namespaces)的进行了 C/U/D 操作后,默认该作用域下所有 select 中的缓存将被 clear。
3.10:什么是 MyBatis 的接口绑定?有哪些实现方式? 1:注解的形式 可以通过@Select、@Update、@Delete、@Insert注解中写上相应的value的sql 来绑定 在@InsertProvider、@SelectProvider、@UpdateProvider、@DeleteProvider中定义class以及method并在相应的class对应的method中返回sql来绑定。
2:xml的形式 可以通过在mapper.xml文件来写上select、update、insert、delete标签写上相应的sql来绑定。
4:加了注释的源码(供参考)
https://github.com/1300375795/mybatis3.4.x
|