大家好,我是酱油君。这是互联网技术岗的分享专题,废话少说,进入正题:
物理分页、逻辑分页两种。
RowBounds 表面是在“所有”数据中检索数据,其实并非是一次性查询出所有数据,因为 MyBatis 是对 jdbc 的封装,在 jdbc 驱动中有一个 Fetch Size 的配置,它规定了每次最多从数据库查询多少条数据,假如你要查询更多数据,它会在你执行 next()的时候,去查询更多的数据。就好比你去自动取款机取 10000 元,但取款机每次最多能取 2500 元,所以你要取 4 次才能把钱取完。只是对于 jdbc 来说,当你调用 next()的时候会自动帮你完成查询工作。这样做的好处可以有效的防止内存溢出。
逻辑分页: 从数据库将所有记录查询出来,存储到内存中,展示当前页,然后数据再直接从内存中获取。优点:效率高;缺点:占用内存比较高。
物理分页: 只从数据库中查询当前页的数据。优点:不占用很多内存;缺点:效率比价低(相比于逻辑分页)。
Mybatis仅支持association关联对象和collection关联集合对象的延迟加载,association指的就是一对一,collection指的就是一对多查询。在Mybatis配置文件中,可以配置是否启用延迟加载lazyLoadingEnabled=true|false。
它的原理是,使用CGLIB创建目标对象的代理对象,当调用目标方法时,进入拦截器方法,比如调用a.getB().getName(),拦截器invoke()方法发现a.getB()是null值,那么就会单独发送事先保存好的查询关联B对象的sql,把B查询上来,然后调用a.setB(b),于是a的对象b属性就有值了,接着完成a.getB().getName()方法的调用。这就是延迟加载的基本原理。
当然了,不光是Mybatis,几乎所有的包括Hibernate,支持延迟加载的原理都是一样的。
一级缓存: 基于 PerpetualCache 的 HashMap 本地缓存,其存储作用域为 Session,当 Session flush 或 close 之后,该 Session 中的所有 Cache 就将清空,默认打开一级缓存。
二级缓存与一级缓存其机制相同,默认也是采用 PerpetualCache,HashMap 存储,不同在于其存储作用域为 Mapper(Namespace),并且可自定义存储源,如 Ehcache。默认不打开二级缓存,要开启二级缓存,使用二级缓存属性类需要实现Serializable序列化接口(可用来保存对象的状态),可在它的映射文件中配置
对于缓存数据更新机制,当某一个作用域(一级缓存 Session/二级缓存Namespaces)的进行了C/U/D 操作后,默认该作用域下所有 select 中的缓存将被 clear。
分页插件的基本原理是使用Mybatis提供的插件接口,实现自定义插件,在插件的拦截方法内拦截待执行的sql,然后重写sql,根据dialect方言,添加对应的物理分页语句和物理分页参数。
Mybatis自定义插件针对Mybatis四大对象(Executor、StatementHandler 、ParameterHandler 、ResultSetHandler )进行拦截,具体拦截方式为:
Mybatis自定义插件必须实现Interceptor接口:
1public interface Interceptor {
2 Object intercept(Invocation invocation) throws Throwable; //拦截器具体处理逻辑方法
3 Object plugin(Object target); //根据签名signatureMap生成动态代理对象
4 void setProperties(Properties properties); //设置Properties属性
5}
自定义插件demo:
xxxxxxxxxx
211// ExamplePlugin.java
2 ({ (
3 type= Executor.class,
4 method = "update",
5 args = {MappedStatement.class,Object.class})})
6public class ExamplePlugin implements Interceptor {
7 public Object intercept(Invocation invocation) throws Throwable {
8 Object target = invocation.getTarget(); //被代理对象
9 Method method = invocation.getMethod(); //代理方法
10 Object[] args = invocation.getArgs(); //方法参数
11 // do something ...... 方法拦截前执行代码块
12 Object result = invocation.proceed();
13 // do something .......方法拦截后执行代码块
14 return result;
15 }
16 public Object plugin(Object target) {
17 return Plugin.wrap(target, this);
18 }
19 public void setProperties(Properties properties) {
20 }
21}
一个@Intercepts可以配置多个@Signature,@Signature中的参数定义如下: