目录:
文章目录
mybatis常用标签使用文档
@author 李思文
mybatis映射文件中是以mapper作为根节点的,只有namespace,其值为对应的Dao层接口的路径,它的结构为:
mapper
– 根节点,绑定Dao层接口cache
– 给定命名空间的缓存配置。cache-ref
– 其他命名空间缓存配置的引用。resultMap
– 是最复杂也是最强大的元素,用来描述如何从数据库结果集中来加载对象。sql
– 可被其他语句引用的可重用语句块。insert
– 映射插入语句update
– 映射更新语句delete
– 映射删除语句select
– 映射查询语句
下边一一介绍其子标签
<cache> 标签
这个标签是定义mybatis二级缓存,其范围是同一个namespace下也就是一个mapper.xml文件,可以被多个SqlSession共享,是一个全局变量。mybatis也有一级缓存, 一级缓存的范围是一个SqlSession,也就是访问一次业务层,就会产生一个SqlSession,共享一级缓存,其一级缓存的生命周期也是和SqlSession一样的,和SqlSession共存亡,但是一级缓存很容易产生脏数据。一级缓存具体内容看另一篇mybatis总结知识点中的7.mybatis的一级缓存和二级缓存
<cache>标签中有 <cache eviction=“FIFO” flushInterval=“60000” size=“512” readOnly=“true” />四个参数
其每个参数的含义为:
1.eviction是缓存回收策略定义,其可用的策略有:
LRU
– 最近最少使用的:移除最长时间不被使用的对象。FIFO
– 先进先出:按对象进入缓存的顺序来移除它们。SOFT
– 软引用:移除基于垃圾回收器状态和软引用规则的对象。WEAK
– 弱引用:更积极地移除基于垃圾收集器状态和弱引用规则的对象。
2.flushInterval(刷新间隔)可以被设置为任意的正整数,而且它们代表一个合理的毫秒 形式的时间段。默认情况是不设置,也就是没有刷新间隔,缓存仅仅调用特殊语句时刷新。
3.size(引用数目)可以被设置为任意正整数,要记住你缓存的对象数目和你运行环境的可用内存资源数目。默认值是 1024。
4.readOnly(只读)属性可以被设置为 true 或 false。只读的缓存会给所有调用者返回缓 存对象的相同实例。因此这些对象不能被修改。这提供了很重要的性能优势。可读写的缓存 会返回缓存对象的拷贝(通过序列化) 。这会慢一些,但是安全,因为更改返回对象,缓存中对象不会被更改,因此默认是 false。 这个是否只读并不是我们所理解的只读,这里是因为返回的相同实例,所以建议只读,这里属性的设置其实是返回对象的方法的设置。
所以上述定义的缓存含义为:创建了一个 FIFO 缓存,并每隔 60 秒刷新,存数结果对象或列表的 512 个引用,而且返回的对象被认为是只读的。
下边举个使用缓存查询的例子:
如果不用 cache,查询的运行结果如下
这里看到是去数据库中查询了两次。
如果用了cache则可以把第一次的查询存到缓存中,第二次可以先到缓存中存取,提升效率,这里cache 的配置为:
<cache eviction="FIFO" flushInterval="60000" size="512" readOnly="true"/>
运行结果如下
第一个红框中说缓存命中率为0,因为是第一次进行查询,所以缓存中并没有这个查询结果,
因为命中率为0所以进行了第二个红框的和数据库的交互,进行了查询操作,查询之之后,将这次操作的结果存入缓存当中,以便下次访问使用。
当第一次查询结束之后,在进行相同的第二次查询操作,因为缓存中有了第一次同样操作的结果,所以在缓存中命中,命中率为0.5,之后不进行和数据库的交互。
再进行增删改的操作后,默认会将缓存清空,如果两次查询中间插入了增删改的操作,第二次查询还是要访问数据库的。例子如下
主要代码为:
List<UserModel> findAllUser(){
int i=1;
int j=1;
int k=1;
List<UserModel> userModels=null;
UserModel userModel=null;
try {
userModels=userService.findAllUser(i++);
userService.inserUser(j++);
userModels=userService.findAllUser(i++);
return userModels;
} catch (Exception e){
System.out.println("查询出错");
return null;
}
}
结果为:
由图可以看出在进行了一次增加操作之后,第二次依然没有命中,命中率为0。
还有以下几点需要注意:
- 二级缓存在多表联查的时候很大可能会产生脏数据,有设计上的缺陷,安全使用二级缓存的条件比较苛刻。因为在第二次查询的时候,在缓存中取值,在此期间,可能该表进行了增删改操作,并不会清除当前缓存,而第二次查询产生脏数据。其解决办法是使用<cache-ref> 标签,引用其缓存空间,这样之后多个Mapper namespace下的所有操作都会对缓存使用造成影响。
- 还有一个问题就是,在分布式环境下,由于默认的MyBatis Cache实现都是基于本地的,分布式环境下必然会出现读取到脏数据,需要使用集中式缓存将MyBatis的Cache接口实现,有一定的开发成本,直接使用Redis,Memcached等分布式缓存可能成本更低,安全性也更高。
- 总的来说这个mybatis 缓存因为脏数据问题,需要谨慎使用。-
- 重点说明这里的命中率是从始至今的总的命中率,而不是当前值的命中率,坑很大这个命中率我一直以为是当前值的命中率。看了源码才知道是从始至今的总的命中率,一下附上命中率计算方法源码。
public Object getObject(Object key)