一级缓存

  Mybatis对缓存提供支持,但是在没有配置的默认情况下,它只开启一级缓存,一级缓存只是相对于同一个SqlSession而言。所以在参数和SQL完全一样的情况下,我们使用同一个SqlSession对象调用一个Mapper方法,往往只执行一次SQL,因为使用SelSession第一次查询后,MyBatis会将其放在缓存中,以后再查询的时候,如果没有声明需要刷新,并且缓存没有超时的情况下,SqlSession都会取出当前缓存的数据,而不会再次发送SQL到数据库。

              

  为什么要使用一级缓存,不用多说也知道个大概。但是还有几个问题我们要注意一下。

  1、一级缓存的生命周期有多长?

  a、MyBatis在开启一个数据库会话时,会 创建一个新的SqlSession对象,SqlSession对象中会有一个新的Executor对象。Executor对象中持有一个新的PerpetualCache对象;当会话结束时,SqlSession对象及其内部的Executor对象还有PerpetualCache对象也一并释放掉。

  b、如果SqlSession调用了close()方法,会释放掉一级缓存PerpetualCache对象,一级缓存将不可用。

  c、如果SqlSession调用了clearCache(),会清空PerpetualCache对象中的数据,但是该对象仍可使用。

  d、SqlSession中执行了任何一个update操作(update()、delete()、insert()) ,都会清空PerpetualCache对象的数据,但是该对象可以继续使用

    2、怎么判断某两次查询是完全相同的查询?

  mybatis认为,对于两次查询,如果以下条件都完全一样,那么就认为它们是完全相同的两次查询。

  2.1 传入的statementId

  2.2 查询时要求的结果集中的结果范围

  2.3. 这次查询所产生的最终要传递给JDBC java.sql.Preparedstatement的Sql语句字符串(boundSql.getSql() )

  2.4 传递给java.sql.Statement要设置的参数值

二级缓存:

  MyBatis的二级缓存是Application级别的缓存,它可以提高对数据库查询的效率,以提高应用的性能。

  MyBatis的缓存机制整体设计以及二级缓存的工作模式

  

  SqlSessionFactory层面上的二级缓存默认是不开启的,二级缓存的开席需要进行配置,实现二级缓存的时候,MyBatis要求返回的POJO必须是可序列化的。 也就是要求实现Serializable接口,配置方法很简单,只需要在映射XML文件配置就可以开启缓存了<cache/>,如果我们配置了二级缓存就意味着:

  • 映射语句文件中的所有select语句将会被缓存。
  • 映射语句文件中的所欲insert、update和delete语句会刷新缓存。
  • 缓存会使用默认的Least Recently Used(LRU,最近最少使用的)算法来收回。
  • 根据时间表,比如No Flush Interval,(CNFI没有刷新间隔),缓存不会以任何时间顺序来刷新。
  • 缓存会存储列表集合或对象(无论查询方法返回什么)的1024个引用
  • 缓存会被视为是read/write(可读/可写)的缓存,意味着对象检索不是共享的,而且可以安全的被调用者修改,不干扰其他调用者或线程所做的潜在修改。

实践:

一、创建一个POJO Bean并序列化

  由于二级缓存的数据不一定都是存储到内存中,它的存储介质多种多样,所以需要给缓存的对象执行序列化。(如果存储在内存中的话,实测不序列化也可以的。)

package com.yihaomen.mybatis.model;

import com.yihaomen.mybatis.enums.Gender;
import java.io.Serializable;
import java.util.List; /**
*  @ProjectName: springmvc-mybatis 
*/
public class Student implements Serializable{ private static final long serialVersionUID = 735655488285535299L;
private String id;
private String name;
private int age;
private Gender gender;
private List<Teacher> teachers;
setters&getters()....;
toString();
}

二、在映射文件中开启二级缓存

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.yihaomen.mybatis.dao.StudentMapper">
<!--开启本mapper的namespace下的二级缓存-->
<!--
eviction:代表的是缓存回收策略,目前MyBatis提供以下策略。
(1) LRU,最近最少使用的,一处最长时间不用的对象
(2) FIFO,先进先出,按对象进入缓存的顺序来移除他们
(3) SOFT,软引用,移除基于垃圾回收器状态和软引用规则的对象
(4) WEAK,弱引用,更积极的移除基于垃圾收集器状态和弱引用规则的对象。这里采用的是LRU,
移除最长时间不用的对形象 flushInterval:刷新间隔时间,单位为毫秒,这里配置的是100秒刷新,如果你不配置它,那么当
SQL被执行的时候才会去刷新缓存。 size:引用数目,一个正整数,代表缓存最多可以存储多少个对象,不宜设置过大。设置过大会导致内存溢出。
这里配置的是1024个对象 readOnly:只读,意味着缓存数据只能读取而不能修改,这样设置的好处是我们可以快速读取缓存,缺点是我们没有
办法修改缓存,他的默认值是false,不允许我们修改
-->
<cache eviction="LRU" flushInterval="100000" readOnly="true" size="1024"/>
<resultMap id="studentMap" type="Student">
<id property="id" column="id" />
<result property="name" column="name" />
<result property="age" column="age" />
<result property="gender" column="gender" typeHandler="org.apache.ibatis.type.EnumOrdinalTypeHandler" />
</resultMap>
<resultMap id="collectionMap" type="Student" extends="studentMap">
<collection property="teachers" ofType="Teacher">
<id property="id" column="teach_id" />
<result property="name" column="tname"/>
<result property="gender" column="tgender" typeHandler="org.apache.ibatis.type.EnumOrdinalTypeHandler"/>
<result property="subject" column="tsubject" typeHandler="org.apache.ibatis.type.EnumTypeHandler"/>
<result property="degree" column="tdegree" javaType="string" jdbcType="VARCHAR"/>
</collection>
</resultMap>
<select id="selectStudents" resultMap="collectionMap">
SELECT
s.id, s.name, s.gender, t.id teach_id, t.name tname, t.gender tgender, t.subject tsubject, t.degree tdegree
FROM
student s
LEFT JOIN
stu_teach_rel str
ON
s.id = str.stu_id
LEFT JOIN
teacher t
ON
t.id = str.teach_id
</select>
<!--可以通过设置useCache来规定这个sql是否开启缓存,ture是开启,false是关闭-->
<select id="selectAllStudents" resultMap="studentMap" useCache="true">
SELECT id, name, age FROM student
</select>
<!--刷新二级缓存
<select id="selectAllStudents" resultMap="studentMap" flushCache="true">
SELECT id, name, age FROM student
</select>
-->
</mapper>

三、在 mybatis-config.xml中开启二级缓存

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<settings>
<!--这个配置使全局的映射器(二级缓存)启用或禁用缓存-->
<setting name="cacheEnabled" value="true" />
.....
</settings>
....
</configuration>

四、测试

package com.yihaomen.service.student;

import com.yihaomen.mybatis.dao.StudentMapper;
import com.yihaomen.mybatis.model.Student;
import com.yihaomen.mybatis.model.Teacher;
import com.yihaomen.service.BaseTest;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import java.util.List; /**
*   
*  @ProjectName: springmvc-mybatis 
*/
public class TestStudent extends BaseTest { public static void selectAllStudent() {
SqlSessionFactory sqlSessionFactory = getSession();
SqlSession session = sqlSessionFactory.openSession();
StudentMapper mapper = session.getMapper(StudentMapper.class);
List<Student> list = mapper.selectAllStudents();
System.out.println(list);
System.out.println("第二次执行");
List<Student> list2 = mapper.selectAllStudents();
System.out.println(list2);
session.commit();
System.out.println("二级缓存观测点");
SqlSession session2 = sqlSessionFactory.openSession();
StudentMapper mapper2 = session2.getMapper(StudentMapper.class);
List<Student> list3 = mapper2.selectAllStudents();
System.out.println(list3);
System.out.println("第二次执行");
List<Student> list4 = mapper2.selectAllStudents();
System.out.println(list4);
session2.commit(); } public static void main(String[] args) {
selectAllStudent();
}
}

结果:

[QC] DEBUG [main] org.apache.ibatis.transaction.jdbc.JdbcTransaction.setDesiredAutoCommit(98) | Setting autocommit to false on JDBC Connection [com.mysql.jdbc.JDBC4Connection@51e0173d]
[QC] DEBUG [main] org.apache.ibatis.logging.jdbc.BaseJdbcLogger.debug(139) | ==> Preparing: SELECT id, name, age FROM student 
[QC] DEBUG [main] org.apache.ibatis.logging.jdbc.BaseJdbcLogger.debug(139) | ==> Parameters: 
[QC] DEBUG [main] org.apache.ibatis.logging.jdbc.BaseJdbcLogger.debug(139) | <== Total: 6
[Student{id='1', name='刘德华', age=55, gender=null, teachers=null}, Student{id='2', name='张惠妹', age=49, gender=null, teachers=null}, Student{id='3', name='谢霆锋', age=35, gender=null, teachers=null}, Student{id='4', name='王菲', age=47, gender=null, teachers=null}, Student{id='5', name='汪峰', age=48, gender=null, teachers=null}, Student{id='6', name='章子怡', age=36, gender=null, teachers=null}]
第二次执行
[QC] DEBUG [main] org.apache.ibatis.cache.decorators.LoggingCache.getObject(62) | Cache Hit Ratio [com.yihaomen.mybatis.dao.StudentMapper]: 0.0
[Student{id='1', name='刘德华', age=55, gender=null, teachers=null}, Student{id='2', name='张惠妹', age=49, gender=null, teachers=null}, Student{id='3', name='谢霆锋', age=35, gender=null, teachers=null}, Student{id='4', name='王菲', age=47, gender=null, teachers=null}, Student{id='5', name='汪峰', age=48, gender=null, teachers=null}, Student{id='6', name='章子怡', age=36, gender=null, teachers=null}]
二级缓存观测点
[QC] DEBUG [main] org.apache.ibatis.cache.decorators.LoggingCache.getObject(62) | Cache Hit Ratio [com.yihaomen.mybatis.dao.StudentMapper]: 0.3333333333333333
[Student{id='1', name='刘德华', age=55, gender=null, teachers=null}, Student{id='2', name='张惠妹', age=49, gender=null, teachers=null}, Student{id='3', name='谢霆锋', age=35, gender=null, teachers=null}, Student{id='4', name='王菲', age=47, gender=null, teachers=null}, Student{id='5', name='汪峰', age=48, gender=null, teachers=null}, Student{id='6', name='章子怡', age=36, gender=null, teachers=null}]
第二次执行
[QC] DEBUG [main] org.apache.ibatis.cache.decorators.LoggingCache.getObject(62) | Cache Hit Ratio [com.yihaomen.mybatis.dao.StudentMapper]: 0.5
[Student{id='1', name='刘德华', age=55, gender=null, teachers=null}, Student{id='2', name='张惠妹', age=49, gender=null, teachers=null}, Student{id='3', name='谢霆锋', age=35, gender=null, teachers=null}, Student{id='4', name='王菲', age=47, gender=null, teachers=null}, Student{id='5', name='汪峰', age=48, gender=null, teachers=null}, Student{id='6', name='章子怡', age=36, gender=null, teachers=null}]

Process finished with exit code 0

我们可以从结果看到,sql只执行了一次,证明我们的二级缓存生效了。

参考:

寻找风口的猪https://www.cnblogs.com/happyflyingpig/

mybatis整合ehcache缓存框架的使用

  mybaits的二级缓存是mapper范围级别,除了在SqlMapConfig.xml设置二级缓存的总开关,还要在具体的mapper.xml中开启二级缓存。

1.开启mybatis的二级缓存

  在核心配置文件SqlMapConfig.xml中加入

1 <settings>
2 <!-- 开启二级缓存 -->
3 <setting name="cacheEnabled" value="true"/>
4 </settings>

2.导入ehcache相关jar包

ehcache-core-2.6.5.jar

mybatis-ehcache-1.0.2.jar

3.在classpath下加入ehcache.xml文件

 1 <ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
2 xsi:noNamespaceSchemaLocation="../config/ehcache.xsd">
3 <diskStore path="F:\develop\ehcache" />
4 <defaultCache
5 maxElementsInMemory="1000"
6 maxElementsOnDisk="10000000"
7 eternal="false"
8 overflowToDisk="false"
9 timeToIdleSeconds="120"
10 timeToLiveSeconds="120"
11 diskExpiryThreadIntervalSeconds="120"
12 memoryStoreEvictionPolicy="LRU">
13 </defaultCache>
14 </ehcache>

属性说明:
 diskStore:指定数据在磁盘中的存储位置。
 defaultCache:当借助CacheManager.add("demoCache")创建Cache时,EhCache便会采用<defalutCache/>指定的的管理策略
以下属性是必须的:
 maxElementsInMemory - 在内存中缓存的element的最大数目 
 maxElementsOnDisk - 在磁盘上缓存的element的最大数目,若是0表示无穷大
 eternal - 设定缓存的elements是否永远不过期。如果为true,则缓存的数据始终有效,如果为false那么还要根据timeToIdleSeconds,timeToLiveSeconds判断
 overflowToDisk - 设定当内存缓存溢出的时候是否将过期的element缓存到磁盘上
以下属性是可选的:
 timeToIdleSeconds - 当缓存在EhCache中的数据前后两次访问的时间超过timeToIdleSeconds的属性取值时,这些数据便会删除,默认值是0,也就是可闲置时间无穷大
 timeToLiveSeconds - 缓存element的有效生命期,默认是0.,也就是element存活时间无穷大
diskSpoolBufferSizeMB 这个参数设置DiskStore(磁盘缓存)的缓存区大小.默认是30MB.每个Cache都应该有自己的一个缓冲区.
 diskPersistent - 在VM重启的时候是否启用磁盘保存EhCache中的数据,默认是false。
 diskExpiryThreadIntervalSeconds - 磁盘缓存的清理线程运行间隔,默认是120秒。每个120s,相应的线程会进行一次EhCache中数据的清理工作
 memoryStoreEvictionPolicy - 当内存缓存达到最大,有新的element加入的时候, 移除缓存中element的策略。默认是LRU(最近最少使用),可选的有LFU(最不常使用)和FIFO(先进先出)

4.在UserMapper.xml中开启二缓存,UserMapper.xml下的sql执行完成会存储到它的缓存区域(HashMap)

  根据需求调整缓存参数:

1 <cache type="org.mybatis.caches.ehcache.EhcacheCache" >
2 <property name="timeToIdleSeconds" value="3600"/>
3 <property name="timeToLiveSeconds" value="3600"/>
4 <!-- 同ehcache参数maxElementsInMemory -->
5 <property name="maxEntriesLocalHeap" value="1000"/>
6 <!-- 同ehcache参数maxElementsOnDisk -->
7 <property name="maxEntriesLocalDisk" value="10000000"/>
8 <property name="memoryStoreEvictionPolicy" value="LRU"/>
9 </cache>

log4j打印如下日志,说明缓存开启成功:

DEBUG [main] - Cache Hit Ratio [cn.itcast.jdbc.mapper.UserMapper]: 0.0

应用场景:
  对于访问多的查询请求且用户对查询结果实时性要求不高,此时可采用mybatis二级缓存技术降低数据库访问量,提高访问速度,业务场景比如:耗时较高的统计分析sql、电话账单查询sql等。
实现方法如下:通过设置刷新间隔时间,由mybatis每隔一段时间自动清空缓存,根据数据变化频率设置缓存刷新间隔flushInterval,比如设置为30分钟、60分钟、24小时等,根据需求而定。

局限性:
  mybatis二级缓存对细粒度的数据级别的缓存实现不好,比如如下需求:对商品信息进行缓存,由于商品信息查询访问量大,但是要求用户每次都能查询最新的商品信息,此时如果使用mybatis的二级缓存就无法实现当一个商品变化时只刷新该商品的缓存信息而不刷新其它商品的信息,因为mybaits的二级缓存区域以mapper为单位划分,当一个商品信息变化会将所有商品信息的缓存数据全部清空。解决此类问题需要在业务层根据需求对数据有针对性缓存。

  缓存都是实现了Cache这个接口.....

  public class EhCache implements Cache{}

转载:http://www.cnblogs.com/little-fly/

Mybatis五(一级二级缓存、第三方缓存)的更多相关文章

  1. Mybatis的一级二级缓存

    Mybatis提供了缓存机制,可以减轻数据库的压力,提高性能 Mybatis的缓存分为两级:一个是一级缓存,一个二级缓存 一级缓存:即默认使用的缓存SqlSession级别的缓存,只在sqlsessi ...

  2. Mybatis学习(五)————— 延迟加载和缓存机制(一级二级缓存)

    一.延迟加载 延迟加载就是懒加载,先去查询主表信息,如果用到从表的数据的话,再去查询从表的信息,也就是如果没用到从表的数据的话,就不查询从表的信息.所以这就是突出了懒这个特点.真是懒啊. Mybati ...

  3. Mybatis(五) 延迟加载和缓存机制(一级二级缓存)

    踏踏实实踏踏实实,开开心心,开心是一天不开心也是一天,路漫漫其修远兮. --WH 一.延迟加载 延迟加载就是懒加载,先去查询主表信息,如果用到从表的数据的话,再去查询从表的信息,也就是如果没用到从表的 ...

  4. MyBatis加强(1)~缓存机制(一级缓存、二级缓存、第三方缓存技术redis、ehcache)

    一.缓存机制 使用缓存可以使应用更快地获取数据,避免频繁的数据库交互操作,尤其是在查询越多,缓存命中率越高 的情况下,缓存的作用就越明显. 1.缓存原理:Map ■ 查询时,先从缓存区查询:找到,返回 ...

  5. [原创]关于mybatis中一级缓存和二级缓存的简单介绍

    关于mybatis中一级缓存和二级缓存的简单介绍 mybatis的一级缓存: MyBatis会在表示会话的SqlSession对象中建立一个简单的缓存,将每次查询到的结果结果缓存起来,当下次查询的时候 ...

  6. Mybatis之一级缓存,二级缓存

    一级缓存:Mybatis的一级缓存在session上,只要通过session查过的数据,都会放在session上,下一次再查询相同id的数据,都直接冲缓存中取出来,而不用到数据库里去取了. 二级缓存: ...

  7. MyBatis的一级缓存和二级缓存简介笔记

    关于mybatis中一级缓存和二级缓存的简单介绍 mybatis的一级缓存: MyBatis会在表示会话的SqlSession对象中建立一个简单的缓存,将每次查询到的结果结果缓存起来,当下次查询的时候 ...

  8. 关于mybatis中一级缓存和二级缓存的简单介绍

    关于mybatis中一级缓存和二级缓存的简单介绍 mybatis的一级缓存: MyBatis会在表示会话的SqlSession对象中建立一个简单的缓存,将每次查询到的结果结果缓存起来,当下次查询的时候 ...

  9. MyBatis的一级缓存和二级缓存

    一级缓存 是SqlSession级别的缓存,当使用了clearCache方法和,或者close方法的话,这个缓存失效,如果还有同样的查询,则还会发送一次查询 SqlSession session = ...

随机推荐

  1. Winfrom DataGridView中使用Tooltip

    第一步:添加DataGridView.Tooltip控件,略 第二步:设置ToolTip 相关属性,略,参考下图 第三步:DataGridView 添加 CellMouseEnter.CellMous ...

  2. 【mysql】索引优化记录

    基础知识 Innodb存储引擎 支持行锁 支持事务: Myisam存储引擎 只支持表锁: 不支持事务: 常见索引列表 独立的列 前缀索引(索引选择性) 多列索引(并不是多个单列索引,索引顺序很重要) ...

  3. win server 2003 x64 IIS配置

    新装IIS第一个报错 The 'Microsoft.Jet.OLEDB.4.0' provider is not registered on the local machine 原因是 服务器 IIS ...

  4. Null hypothesis TypeⅠerror Type Ⅱ error

    Null hypothesis usually express the phenomenon of no effect or no difference. TypeⅠerror is the inco ...

  5. itertools库中product函数用法 (即可以随机出所有组合,因果图那样的)

  6. 服务注册发现consul之二:在Spring Cloud中使用Consul实现服务的注册和发现

    首先安装consul环境,参照之前的文章:<服务注册发现consul之一:consul介绍及安装>中的第一节介绍. Spring Cloud使用Consul的服务与发现 1.导入依赖pri ...

  7. mvc5总结(1)

    1.Global.asax 全局的启动项,初始化相关配置 2.路由,按照默认规定请求就行,没必要扩展太多 3.区域路由,当我们想命名相同的controller和action时,结合命名空间使用 pub ...

  8. js对象-平铺与嵌套的互相转换

    一个json对象,包含嵌套关系,传输过来的时候是平铺的,顺序打乱,用parentCode属性来关联,如下 { "1":{ "name": "中国&qu ...

  9. Xmanager远程连接CentOS7

    上周例会,又被说了一通,Xmanager远程连接的文档没写?服务没搭建?心想这都有VNC了,为毛一定要弄这个啊?!!但是,我还是在今天给弄了,╮(╯▽╰)╭没人权.搭建完尝试用了下,感觉吧,也不咋地啊 ...

  10. arp协议分析&python编程实现arp欺骗抓图片

    arp协议分析&python编程实现arp欺骗抓图片 序 学校tcp/ip协议分析课程老师布置的任务,要求分析一种网络协议并且研究安全问题并编程实现,于是我选择了研究arp协议,并且利用pyt ...