缓存

8、查询缓存(二级缓存)(mybatis笔记)

2016-06-28  本文已影响517人  yjaal

一、原理

1

二、测试

<settings>
    <!-- 打开延迟加载的开关,再将积极加载改为消极加载(即按需加载) -->
    <setting name="lazyLoadingEnabled" value="true"/>
    <setting name="aggressiveLazyLoading" value="false"/>
    <!-- 开启二级缓存,这里设置是为了方便管理,本身默认是开启的 -->
    <setting name="cacheEnabled" value="true"/>
</settings>

UserMapper.xml

<!-- 开启本mapper的namespace下的二级缓存 -->
<cache />

说明:其实在全局配置文件中配置主要是为了便于管理。在UserMapper.xml中开启二级缓存,UserMapper.xml下的sql执行完成会存储到它的缓存区域(HashMap)。

索引 描述 允许值 默认值
cacheEnabled 对在此配置文件下的所有cache进行全局性开/关设置 true/false true
public class User implements Serializable{
    private Integer id ;
    private String username ;
    private String sex ;
    private Date birthday ;
    private String address ;
    //用户创建的订单列表
    private List<Orders> ordersList ;
....
}
//二级缓存测试
@Test
public void testCache2() throws Exception{
    SqlSession sqlSession1 = sqlSessionFactory.openSession();
    SqlSession sqlSession2 = sqlSessionFactory.openSession();
    SqlSession sqlSession3 = sqlSessionFactory.openSession();
    
    UserMapper userMapper1 = sqlSession1.getMapper(UserMapper.class);   
    //第一次发起请求,查询id为1的用户
    User user1 = userMapper1.findUserById(1);
    System.out.println(user1);
    sqlSession1.close();//如果不关闭,SqlSession数据是不能写到二级缓存区域的

    UserMapper userMapper2 = sqlSession2.getMapper(UserMapper.class);   
    //第二次发起请求,查询id为1的用户
    User user2 = userMapper2.findUserById(1);
    System.out.println(user1);
    sqlSession2.close();
}

此时的测试结果为:

2
可以看到总共只是发出了一条sql语句,同时注意到有一项信息Cache Hit Retio,这表示缓存命中率,第一次的时候缓存中没有数据则命中率是0.0,第二次先从一级缓存中找,没有;再从二级缓存中找,找到了,此时缓存命中率是0.5。
//二级缓存测试
@Test
public void testCache2() throws Exception{
    SqlSession sqlSession1 = sqlSessionFactory.openSession();
    SqlSession sqlSession2 = sqlSessionFactory.openSession();
    SqlSession sqlSession3 = sqlSessionFactory.openSession();
    
    UserMapper userMapper1 = sqlSession1.getMapper(UserMapper.class);   
    //第一次发起请求,查询id为1的用户
    User user1 = userMapper1.findUserById(1);
    System.out.println(user1);
    sqlSession1.close();//如果不关闭,SqlSession数据是不能写到二级缓存区域的
    
    //执行提交操作
    UserMapper userMapper3 = sqlSession3.getMapper(UserMapper.class);   
    User user = userMapper3.findUserById(1);
    user.setUsername("狗蛋");
    userMapper3.updateUser(user);
    sqlSession3.commit();//执行提交清空UserMapper下的二级缓存
    sqlSession3.close();

    UserMapper userMapper2 = sqlSession2.getMapper(UserMapper.class);   
    //第二次发起请求,查询id为1的用户
    User user2 = userMapper2.findUserById(1);
    System.out.println(user1);
    sqlSession2.close();

}

此时我们在测试的时候就会发现发出了两条查询语句。

三、二级缓存其他一些参数

3.1 禁用二级缓存

<select id="findOrderListResultMap" resultMap="ordersUserMap" userCache = "false">

总结:针对每次查询都需要最新的数据,要设置成禁用二级缓存。

3.2 刷新缓存

<insert id="insertUser" parameterType="User" flushCache="true">

注意:这里刷新缓存就是清空缓存。
总结:一般情况下,执行完commit操作都需要刷新缓存,flushCache="true"表示刷新缓存,这样可以避免数据库脏读。

3.3 Mybatis Cache参数

<cache eviction="FIFO" flushInterval="60000" size="512" readOnly="true"/>

这个更高级的配置创建了一个FIFO缓存,并每隔60秒刷新,存储结果对象或列表的512个引用,而且返回的对象被认为是只读,因此在不同线程中的调用者之间修改它们会导致冲突。可用的解决策略有,默认的是LRU

3.4 整合EhCache

EhCache是一个分布式的缓存框架。即使我们使用mybatis的二级缓存,查询出来的相关数据也只是保存在单个服务器上,所以我们需要使用分布式的缓存。

ehcache-core-2.6.8.jar
mybatis-ehcache-1.0.3.jar
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:noNamespaceSchemaLocation="../config/ehcache.xsd">
    <diskStore path="E:\ehcache" />
    <defaultCache 
        maxElementsInMemory="10000" 
        eternal="false"
        overflowToDisk="false"
        timeToIdleSeconds="120" 
        timeToLiveSeconds="120" 
        maxElementsOnDisk="10000000"
        diskExpiryThreadIntervalSeconds="120" 
        memoryStoreEvictionPolicy="LRU">
    </defaultCache>
</ehcache>
<!-- 开启本mapper的namespace下的二级缓存,
type指定cache接口的实现类的接口,mybatis默认使用PerpetualCache类,我们要和
EhCache整合,需要配置type为EhCache的实现cache接口的类 -->
<cache type="org.mybatis.caches.ehcache.EhcacheCache"/>

之前我们只是开启了二级缓存,默认是使用mybatis的二级缓存,这里我们配置使用EhCache缓存。

四、二级缓存的应用场景

五、局限性

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

上一篇下一篇

猜你喜欢

热点阅读