mybatis 缓存

6. MyBatis缓存

1. 一级缓存: 基于PerpetualCache 的 HashMap本地缓存,其生命周期为 Session,当 Session flush 或 close 之后,该Session中的所有 Cache 就将清空。

2. 二级缓存与一级缓存其机制相同,默认也是采用 PerpetualCache,HashMap存储,不同在于其存储作用域为 Mapper(Namespace),并且可自定义存储源,如 Ehcache。

3. 对于缓存数据更新机制,当某一个作用域(一级缓存Session/二级缓存Namespaces)进行了 C/U/D 操作后,默认该作用域下所有 select 中的缓存将被clear。

面试必考

1.缓存应用场景

查询频率比较高,而且数据信息不经常变动。客户档案定义 ,托运部定义。

2.缓失效的问题

缓存是有过期事件的 。

滑动过期:从最后一次使用开始往后推算一段时间

绝对过期:一段时间内一定会失效

3.缓存是一把双刃剑

哲学:缓存,快,高速,

容易炸,使用不当,起不到加速查询的作用。

Redis ----------->D

4.缓存的存储结构

session 的底层map集合 key value

5.第三方缓存插件

EhCache

查询缓存的使用,主要是为了提高查询访问速度。将用户对同一数据的重复查询过程简化,不再每次均从数据库查询获取结果数据,从而提高访问速度。

6.1 缓存原理
6.2 缓存分类

MyBatis查询缓存机制。根据缓存区的作用域与生命周期,可划分为两种:一级缓存和二级缓存。

  MyBatis查询缓存的作用域是根据映射文件的namespace划分的,相同的namespace的mapper查询数据放在同一个缓存区域。不同namespace下的数据互不干扰。无论是一级缓存还是二级缓存,都是按照namespace进行分别存放的。

  但是一级、二级缓存的不同之处在于,SqlSession一旦关闭,则SqlSession中的数据将不存在,即一级缓存就不复存在。而二级缓存的生命周期与整个应用同步,与SqlSession是否关闭无关。换句话说,一级缓存是在同一线程(同一SqlSession)间共享数据,而二级缓存是在不同线程(不同的SqlSession)间共享数据。

6.3 一级缓存
6.3.1 一级缓存--从缓存中查找数据的依据:

缓存的底层实现是一个Map,Map的value是查询结果

Map的key,即查询依据,使用的ORM架构不同,查询依据是不同的

MyBatis的查询依据是:Sql的id+SQL语句

Hibernate的查询依据是:查询结果对象的id

测试:

@Test

public void show(){

List<Result> list=null;

SqlSession session= UtilMybatis.getsession();

try {

list= session.getMapper(ResultDao.class).findAllResult();

} catch (Exception e) {

e.printStackTrace();

}

for(Result result:list){

System.out.println(result);

}

System.out.println("==========一级缓存===========");

try {

list= session.getMapper(ResultDao.class).findAllResult();

} catch (Exception e) {

e.printStackTrace();

}finally {

UtilMybatis.closesession(session);

}

for(Result result:list){

System.out.println(result);

}

}

结果:sql只执行一次后将id与sql 存储在一级缓存内(使用同一个session)

6.3.2 增、删、改对一级缓存的影响

增删改会清空一级缓存:注意:必须使用insert标签,不能使用select,否则实验做不成功

测试:

public void show() throws Exception {

List<Result> list=null;

SqlSession session= UtilMybatis.getsession();

try {

list= session.getMapper(ResultDao.class).findAllResult();

} catch (Exception e) {

e.printStackTrace();

}

for(Result result:list){

System.out.println(result);

}

System.out.println("==========增加===========");

Result result1=new Result();

result1.setAge(18);

result1.setScore(80);

result1.setSubjectName("shuxue");

Integer count=session.getMapper(ResultDao.class).adderesult(result1);

System.out.println(count);

System.out.println("==========一级缓存===========");

try {

list= session.getMapper(ResultDao.class).findAllResult();

} catch (Exception e) {

e.printStackTrace();

}finally {

UtilMybatis.closesession(session);

}

for(Result result:list){

System.out.println(result);

}

}

结果:session用同一个,在添加后在查询因(增加清空一级缓存)故在进行db查询

6.3.2 内置二级缓存(在同一mapper.xml文件中)

       由于MyBatis从缓存中读取数据的依据与SQL的id相关,而非查询出的对象。所以,使用二级缓存的目的,不是在多个查询间共享查询结果(所有查询中只要查询结果中存在该对象,就直接从缓存中读取,这是对查询结果的共享,Hibernate中的缓存就是为了在多个查询间共享查询结果,但MyBatis不是),而是为了防止同一查询(相同的Sql id,相同的sql语句)的反复执行。

https://my.oschina.net/KingPan/blog/280167

http://www.mamicode.com/info-detail-890951.html

http://blog.csdn.net/isea533/article/details/44566257

http://blog.csdn.net/u010676959/article/details/43953087

http://blog.csdn.net/xiadi934/article/details/50786293

如何开启二级缓存,二级缓存在Mybatis默认是开启(全局配置的某个属性值为true)的,但是开始和能直接使用时两码事。

1.你cacheEnabled=true,默认值为true

<setting name="cacheEnabled" value="true"></setting>

2.你得在Mapper文件中,<cache/>

<cache

eviction="FIFO"

flushInterval="60000"

size="512"

readOnly="true"/>

这个更高级的配置创建了一个 FIFO 缓存,并每隔 60 秒刷新,存数结果对象或列表的 512 个引用,

而且返回的对象被认为是只读的

3.Entity Implements Serializable(实体类序列化)

缓存中对象可用的收回策略

LRU – 最近最少使用的:移除最长时间不被使用的对象。

FIFO – 先进先出:按对象进入缓存的顺序来移除它们。

SOFT – 软引用:移除基于垃圾回收器状态和软引用规则的对象。

WEAK – 弱引用:更积极地移除基于垃圾收集器状态和弱引用规则的对象。

默认的是 LRU。

flushInterval(刷新间隔)可以被设置为任意的正整数,而且它们代表一个合理的毫秒 

形式的时间段。默认情况是不设置,也就是没有刷新间隔,缓存仅仅调用语句时刷新。

size(引用数目)可以被设置为任意正整数,要记住你缓存的对象数目和你运行环境的 

可用内存资源数目。默认值是 1024。

readOnly(只读)属性可以被设置为 true 或 false。只读的缓存会给所有调用者返回

缓 存对象的相同实例。因此这些对象不能被修改。这提供了很重要的性能优势。

可读写的缓存 会返回缓存对象的拷贝(通过序列化) 。这会慢一些,但是安全,因此默认是 false。

6.3.4. 增删改对二级缓存的影响

 1.增删改也会清空二级缓存

      2.对于二级缓存的清空实质上是对value清空为null,key依然存在,并非将Entry<k,v>删除

      3.从DB中进行select查询的条件是:

              1.缓存中根本不存在这个key

              2.存在key对应的Entry,但是value为null

二级缓存的关闭

全局关闭:

局部关闭

二级缓存的使用原则

1.多个namespace不要操作同一张表

2.查询大于修改的情况下使用

6.3.5 引入第三方插件Mybatis集成EhCache

在MyBatis中通过ehcache配置二级缓存

1.jar包

<dependency>

<groupId>net.sf.ehcache</groupId>

<artifactId>ehcache</artifactId>

<version>2.10.4</version>

</dependency>

<dependency>

<groupId>org.mybatis.caches</groupId>

<artifactId>mybatis-ehcache</artifactId>

<version>1.1.0</version>

</dependency>

   2.在小配置中添加一个缓存类

在小配置中输入EhcacheCache 并选中 双击shift

点击EhcacheCache 出现

鼠标右击出现

粘贴在

粘贴前:

粘贴后:

   3.在src下植入ehcache.xml文件

<ehcache>

<diskStore path="java.io.tmpdir"/>

<defaultCache

maxElementsInMemory="10000"

eternal="false"

timeToIdleSeconds="120"

timeToLiveSeconds="120"

overflowToDisk="true"

/>

<cache name="sampleCache1"

maxElementsInMemory="10000"

eternal="false"

timeToIdleSeconds="300"

timeToLiveSeconds="600"

overflowToDisk="true"

/>

<cache name="sampleCache2"

maxElementsInMemory="1000"

eternal="true"

timeToIdleSeconds="0"

timeToLiveSeconds="0"

overflowToDisk="false"

/> -->

</ehcache>

测试: public void show() throws Exception {

List<Result> list=null;

SqlSession session= UtilMybatis.getsession();

try {

list= session.getMapper(ResultDao.class).findAllResult();

} catch (Exception e) {

e.printStackTrace();

}finally {

UtilMybatis.closesession(session); //session关闭

}

for(Result result:list){

System.out.println(result);

}

System.out.println("========二级缓存=============");

SqlSession session1= UtilMybatis.getsession();

try {

list= session1.getMapper(ResultDao.class).findAllResult();

} catch (Exception e) {

e.printStackTrace();

}finally {

UtilMybatis.closesession(session1);

}

for(Result result:list){

System.out.println(result);

}

}

结果:sql语句执行一次

原文地址:https://www.cnblogs.com/Java60-123456/p/10678654.html