mybatis 缓存机制
一级缓存搞不定再用二级缓存(内部机制)
- 如果是同一个sqlsession对象进行多次重复的查询,则直接进入一级缓存查询
- 如果不是同一个sqlsession对象进行多次重复的查询(但均来自同一个namespace),则进入二级缓存查询
一级缓存(默认开启)
如果用同样的SqlSession对象查询相同的数据,则只会在第一次 查询时 向数据库发送SQL语句,并将查询的结果 放入到sqlsession中(作为缓存存在);后续再次查询该同样的对象时,则直接从缓存中查询该对象即可(即省略了重复的数据库的访问)
举例说明:第一次查询zs这个人,他的信息会存储在sqlsession中,后面如果还要同样的查询,那个就不会再从数据库查询,而是直接在sqlsession中取;
但是一旦执行了commit() 方法,sqlsession就会立即被清空。
(一级缓存是mybatis内置的,默认开启,不需要手动设置。)
- 一级缓存起作用(SQL语句只执行了一次)
- commit() 执行后(执行了两次SQL)
二级缓存
(commit()方法同样适用于二级缓存,也可以关闭缓存)
MyBatis自带的二级缓存(默认关闭)
【同一个namespace】生成的mapper对象,同享一个缓存。
namespace的值 就是对应mapper接口的全类名(包名.类名), 通过接口可以产生代理对象(XxxMapper对象)
- a. 配置conf.xml
<!-- 开启二级缓存 -->
<setting name="cacheEnabled" value="true"/>
- b.在具体的mapper.xml中声明开启
<mapper namespace="org.lanqiao.mapper.StudentMapper">
<!-- 声明次namespace开启二级缓存 -->
<cache/>
运行可能会出现NotSerializableException异常,这是因为二级缓存是在硬盘上,因此需要将实体类序列化 ,以及类的级联属性、和父类(序列化:即将数据由内存转到硬盘上)
触发将对象写入二级缓存的时机:SqlSession对象的close()方法。
开启成功后(只执行一次SQL)
namespace决定了studentMapper对象的产生
-
清理方式:
- 1.在二级缓存中,commit会清理一级和二级缓存;但是清理二级缓存时,不能是查询自身的commit,否者清除无效(即除去查询以外其他的sqlsession的commit()方法)
- 2.在select标签中 增加属性 flushCache=“true”,与commit()效果一致
-
注意:
- 二级缓存 的范围是同一个namespace, 如果有多个xxMapper.xml的namespace值相同,则通过这些xxxMapper.xml产生的xxMapper对象 仍然共享二级缓存。
-
缓存禁用 :
- select标签中useCache=“false”,在具体select标签中使用,表示该标签所对应的SQL放(true) 或 不放入缓存(false)
-
结论:
- 只要产生的xxxMapper对象 来自于同一个namespace,则 这些对象 共享二级缓存。
- 清空缓存机制(commit())设计的目的是为了防止脏数据
举例说明:当查询一个用户数据后,系统会将数据存放在缓存中,如果执行增删改语句,数据库中的值发生了改变,但是再次查询这个用户信息时,依然会从缓存中获取,而缓存中的数据与更新后的并不一致,这时就产生了脏数据
第三方的二级缓存
常用的有:ehcache、memcache(内部已经实现了cache接口)
要想整合三方提供的二级缓存 (或者自定义二级缓存),必须实现org.apache.ibatis.cache.Cache接口,该接口的默认实现类PerpetualCache
具体的下次步骤需要的可以留言,有需要的话会补充
就说到这了。。。