mybatis提供查询缓存,用于减轻数据压力,提升数据库性能
mybatis提供一级缓存二级缓存
一级缓存是SQLSession级别的缓存
在操做数据库时须要构造SQLSession对象,在对象中有一个数据结构(HashMap)用户存储缓存数据
不一样的SQLSession之间的缓存数据的区域(HashMap)是互不影响的。
二级缓存是mapper级别的缓存
多个SQLSession去操做同一个Mapper的sql语句,多个SqlSession能够共用二级缓存,二级缓存是SQLSession的
为何要存储?
若是缓存中有数据就不用在从数据库中获取,大大提升系统的性能。
1234567891011121314复制代码
2.1一级缓存的工做原理
第一次发起查询用户id为1的用户的信息,先去找缓存中是否有id为1的用户信息,若是没有,从数据库查询用户
信息
获得用户信息,将用户信息存储到一级存储中
若是在SQLSession去执行commit操做(执行插入,更新,删除)清空SQLSession中的一级缓存。这样作的目的
为了缓存中永远存储的是最新的信息,避免脏读
第二次发起查询用户id为1的用户信息,先去查询缓存中是否有id为1的用户信息,缓存中有,直接从缓存中获取
用户信息
2.2一级缓存测试
mybatis默认支持一级缓存,不须要在配置文件去配置
按照上边一级缓存原理步骤测试
12345678910111213复制代码
测试代码
public testCacher1() throws Exception{
SqlSession sqlSesssion=sqlSessionFactory.openSession();//建立代理对象
UserMapper userMapper=sqlSession.getMapper(UserMapper.class);
//下边查询使用一个SqlSession
//第一次发起请求,查询id为1的用户
User uyser=userMapper.findUserById(1);
System.out.println(:user1);
//若是SQLSession去执行commit操做(执行插入,更新,删除) 清空SQLSession中的一级缓存
这样作的目的是为了让缓存中存储的是最新的信息,避main脏读
//更新user的信息
user.setUsername(“测试用户22”);
userMapper.updateUser(user1);
//执行commint操做去清除缓存
SQLSession.commit();
//第二次发起请求,查询id为1的用户
User user2=username.fiondUserById(1);
System.out.println(user2);
sqlSession.close();
}123456789101112131415161718192021复制代码
2.3一级缓存的应用
正式开发,是将mybatis和spring进行整合开发,事务空载子service中
一个service方法中包括不少mapper方法调用
service
//开始执行执行时,开启事务,建立SQLSession对象
//第一调用mapper的方法findUserByID(1);
//第二次调用mapper的方法findUserByID(1);从一级缓存中取数据
//方法结束sqlSession关闭
若是是俩次service调用查询相同的用户信息,不走一级缓存,由于service方法结束,SQLSession就关闭
一级缓存就清空。
1234567891011复制代码
首先开启mybatis的二级缓存
SQLSession去查询用户id为1的用户信息,查询到用户信息会将查询数据存储到二级缓存中
若是SQLSession去执行相同mapper下sql,执行commit提交,清空该mapper下的二级缓存区域的数据
SQLSession去查询用户id为1的用户信息,去缓存中查中是否存在数据,若是存在直接从缓存中取出数据
二级缓存与一级缓存区别:二级缓存的范围更大,多个SQLSession能够共享一个UserMapper二级缓存
UserMapper有一个二级缓存区域(按照namespace分),其余的mapper也有本身的缓存区域(按照namespace分)
每个namespace的mapper有一个二级缓存区域,若是俩个mapper的namespace若是相同,这俩个
mapper执行sql查询到的数据就存在相同的二级缓存区域中
3.1开启二级缓存
12345678910复制代码
mybatis的二级缓存是mapper范围级别,除了在SqlMapConfig.xml设置二级缓存的总开关,还要在具体的mapper.xml
中开启二级缓存
二级缓存使用,须要在主文件中进行配置:
①启用二级缓存
<!-- 启用二级缓存 -->
<setting name="cacheEnabled" value="true"/>
在UserMapper中开启二级缓存,UserMapper.xml下的sql执行完成会存储到它的缓存区域(HashMap)、
<mapper namespace="mybaties.mapper.User,apper">
<!--开启本mapper的namespace下的二级缓存-->
<cache/>1234567891011复制代码
3.2调用pojo类实现序列化接口
12复制代码
public class User implements Serializables{
private int id;
private String username;
private String sex;
private Date birthday;
private String address;
}1234567复制代码
为了将缓存的数据取出执行序列化操做,由于二级缓存的存储介质多种多样,不必定在内存
3.3测试方法
1234复制代码
public testCacher2() throws Exception{
SqlSession sqlSesssion=sqlSessionFactory.openSession();
SqlSession sqlSesssion2=sqlSessionFactory.openSession();
SqlSession sqlSesssion3=sqlSessionFactory.openSession();
//建立代理对象
UserMapper userMapper=sqlSession.getMapper(UserMapper.class);
//下边查询使用一个SqlSession
//第一次发起请求,查询id为1的用户
User uyser=userMapper.findUserById(1);
System.out.println(:user1);
//这里执行关闭操做,将SQLSession中的数据写到二级缓存区域
SQLSession.close();
//使用SQLSession执行commit()操做
UserMapper userMapper3=sqlSession3.getMapper(UserMapper.class);
User user=userMapper3.findUserById(1);
user.setUsername(“测试用户22”);
userMapper3.updateUser(user1);
//执行commint操做去清除缓存
SQLSession3.commit();
SQLSession3.close();
UserMapper userMapper2=sqlSession2.getMapper(UserMapper.class);
//第二次发起请求,查询id为1的用户
User user2=userMapper2.findUserById(1);
Stystem.out.println(user2);
sqlSession2.close();
}
123456789101112131415161718192021222324252627282930313233复制代码
3.4useCache配置
①.设置useCache=false能够禁用当前select语句的二级缓存,即每次查询都会发出sql去查询,默认状况是true,即该sql使用二级缓存。
<select id="findOrderListResultMap" resultMap="ordersUserMap" useCache="false">
总结:针对每次查询都须要最新的数据sql,要设置成useCache=false,禁用二级缓存。
②.清空缓存
<insert id="insertUser" parameterType="cn.itcast.mybatis.po.User" flushCache="true">
总结:通常下执行完commit操做都须要刷新缓存,flushCache=true表示刷新缓存,这样能够避免数据库脏读。
注意:
(1)当为select语句时:
flushCache默认为false,表示任什么时候候语句被调用,都不会去清空本地缓存和二级缓存。
useCache默认为true,表示会将本条语句的结果进行二级缓存。
(2)当为insert、update、delete语句时:
flushCache默认为true,表示任什么时候候语句被调用,都会致使本地缓存和二级缓存被清空。
useCache属性在该状况下没有。
当为select语句的时候,若是没有去配置flushCache、useCache,那么默认是启用缓存的,因此,若是有必要,那么就须要人工修改配置
4.mybatis整合ehcache
4.1分布式缓存
咱们系统为了提升系统并发,性能。通常对系统进行分布式部署。(集群部署方式)
不使用分布缓冲池缓存的数据在各自服务器单独存储,不方便系统开发,因此要对分布式缓存对缓存数据进行集中管理
mybatis没法实现分布式缓存。须要和其余分布式缓存框架进行整合
4.2整合的方法
mybatis提供了一个cache接口,若是要实现本身的存储逻辑,实现cache接口开发便可
mybatis和ehcache整合,mybatis和ehcache集合包中提供了一个cache接口的实现类
1234567891011121314151617181920212223242526272829303132复制代码
public interface Cache{
String getId();
void putObject(Object key ,Object value);
Object getObject(Object key);
}
mybatis默认实现的cache类是
public class PerpetualCache implements Cache{
private String id;
private Map<Object,Object> cache=new HashMap<Object,Object>();
public PerpetualCache(String id){
this.id=id;
}
public String getId(){
return id;
}
}
123456789101112131415161718192021复制代码
4.3配置信息
12复制代码
配置mapper中的cache中的type为ehcache对cache接口的实现
<mapper namespace="mybatis.mapper.UserMapper">
<!-- 开启mapper的namespace下的二级缓存
type:指定Cache接口的实现类的类型,mybatis默认使用PerpetualCache
要和ehcache整合:须要配置type为ehcache实现cache接口类型
-->
<caahe type="org.mybatis.caches.ehcache.EhcacheCache"/>1234567复制代码
3.4加入ehcache包
ehcache-core-2.6.5.jar
mybatis-ehcache-1.0.2jar
3.5加入ehcache的配置文件
123456复制代码
在classpath下配置
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> 123456789101112131415复制代码
属性说明:
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二级缓存应用场景
应用场景:
123456789101112131415161718复制代码
对于访问多的查询请求且用户对查询结果实时性要求不高,此时可采用mybatis二级缓存技术下降数据库访问量,提升访
问速度,业务场景好比:耗时较高的统计分析sql、电话帐单查询sql等。实现方法以下:经过设置刷新间隔时间,由mybatis每隔一段时
间自动清空缓存,根据数据变化频率设置缓存刷新间隔flushInterval,好比设置为30分钟、60分钟、24小时等,根据需求而定。spring
5.局限性:
mybatis二级缓存对细粒度的数据级别的缓存实现很差,好比以下需求:对商品信息进行缓存,因为商品信息查询访问量大,
可是要求用户每次都能查询最新的商品信息,此时若是使用mybatis的二级缓存就没法实现当一个商品变化时只刷新该商品的缓
存信息而不刷新其它商品的信息,由于mybaits的二级缓存区域以mapper为单位划分,当一个商品信息变化会将全部商品信息
的缓存数据所有清空。解决此类问题须要在业务层根据需求对数据有针对性缓存。复制代码