Redis实现Mybatis的二级缓存

2018-01-03 11:31:45来源:oschina作者:Michaelyn人点击

分享
一、Mybatis的缓存

通大多数ORM层框架一样,Mybatis自然也提供了对一级缓存和二级缓存的支持。一下是一级缓存和二级缓存的作用于和定义。


1、一级缓存是SqlSession级别的缓存。在操作数据库时需要构造 sqlSession对象,在对象中有一个(内存区域)数据结构(HashMap)用于存储缓存数据。不同的sqlSession之间的缓存数据区域(HashMap)是互相不影响的。


二级缓存是mapper级别的缓存,多个SqlSession去操作同一个Mapper的sql语句,多个SqlSession去操作数据库得到数据会存在二级缓存区域,多个SqlSession可以共用二级缓存,二级缓存是跨SqlSession的。


2、一级缓存的作用域是同一个SqlSession,在同一个sqlSession中两次执行相同的sql语句,第一次执行完毕会将数据库中查询的数据写到缓存(内存),第二次会从缓存中获取数据将不再从数据库查询,从而提高查询效率。当一个sqlSession结束后该sqlSession中的一级缓存也就不存在了。Mybatis默认开启一级缓存。


二级缓存是多个SqlSession共享的,其作用域是mapper的同一个namespace,不同的sqlSession两次执行相同namespace下的sql语句且向sql中传递参数也相同即最终执行相同的sql语句,第一次执行完毕会将数据库中查询的数据写到缓存(内存),第二次会从缓存中获取数据将不再从数据库查询,从而提高查询效率。Mybatis默认没有开启二级缓存需要在setting全局参数中配置开启二级缓存。


一般的我们将Mybatis和Spring整合时,mybatis-spring包会自动分装sqlSession,而Spring通过动态代理sqlSessionProxy使用一个模板方法封装了select()等操作,每一次select()查询都会自动先执行openSession(),执行完close()以后调用close()方法,相当于生成了一个新的session实例,所以我们无需手动的去关闭这个session(),当然也无法使用mybatis的一级缓存,也就是说mybatis的一级缓存在spring中是没有作用的。


因此我们一般在项目中实现Mybatis的二级缓存,虽然Mybatis自带二级缓存功能,但是如果实在集群环境下,使用自带的二级缓存只是针对单个的节点,所以我们采用分布式的二级缓存功能。一般的缓存NoSql数据库如redis,Mancache等,或者EhCache都可以实现,从而更好地服务tomcat集群中ORM的查询。

二、Mybatis的二级缓存的实现

下面主要通过Redis实现Mybatis的二级缓存功能。


1、配置文件中开启二级缓存

[html]view plaincopy

默认二级缓存是开启的。


2、实现Mybatis的Cache接口

Mybatis提供了第三方Cache实现的接口,我们自定义MybatisRedisCache实现Cache接口,代码如下:

[java]view plaincopy

/**
*创建时间:2016年1月7日上午11:40:00
*
*Mybatis二级缓存实现类
*
*@authorandy
*@version2.2
*/publicclassMybatisRedisCacheimplementsCache{privatestaticfinalLoggerLOG=Logger.getLogger(MybatisRedisCache.class);privatefinalReadWriteLockreadWriteLock=newReentrantReadWriteLock(true);privateRedisTemplateredisTemplate=(RedisTemplate)SpringContextHolder.getBean("redisTemplate");privateStringid;privateJdkSerializationRedisSerializerjdkSerializer=newJdkSerializationRedisSerializer();publicMybatisRedisCache(finalStringid){
if(id==null){
thrownewIllegalArgumentException("CacheinstancesrequireanID");
}
LOG.info("RedisCacheid"+id);
this.id=id;
}@Override
publicStringgetId(){
returnthis.id;
}@Override
publicvoidputObject(Objectkey,Objectvalue){
if(value!=null){
redisTemplate.opsForValue().set(key.toString(),jdkSerializer.serialize(value),2,TimeUnit.DAYS);
}
}@Override
publicObjectgetObject(Objectkey){
try{
if(key!=null){
Objectobj=redisTemplate.opsForValue().get(key.toString());
returnjdkSerializer.deserialize((byte[])obj);
}
}catch(Exceptione){
LOG.error("redis");
}
returnnull;
}@Override
publicObjectremoveObject(Objectkey){
try{
if(key!=null){
redisTemplate.expire(key.toString(),1,TimeUnit.SECONDS);
}
}catch(Exceptione){
}
returnnull;
}@Override
publicvoidclear(){
//jedisnonsupport
}@Override
publicintgetSize(){
Longsize=redisTemplate.getMasterRedisTemplate().execute(newRedisCallback(){
@Override
publicLongdoInRedis(RedisConnectionconnection)
throwsDataAccessException{
returnconnection.dbSize();
}
});
returnsize.intValue();
}@Override
publicReadWriteLockgetReadWriteLock(){
returnthis.readWriteLock;
}}
3、二级缓存的实用

我们需要将所有的实体类进行序列化,然后在Mapper中添加自定义cache功能。



[html]view plaincopy

type="org.andy.shop.cache.MybatisRedisCache"
eviction="LRU"
flushInterval="6000000"
size="1024"
readOnly="false"
/>4、Redis中的存储

redis会自动的将Sql+条件+Hash等当做key值,而将查询结果作为value,只有请求中的所有参数都符合,那么就会使用redis中的二级缓存。其查询结果如下:


微信扫一扫

第七城市微信公众平台