Redis实现Mybatis的二级缓存

一、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、配置文件中开启二级缓存

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

   默认二级缓存是开启的。

2、实现Mybatis的Cache接口

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

  1. /** 
  2.  * 创建时间:2016年1月7日 上午11:40:00 
  3.  *  
  4.  * Mybatis二级缓存实现类 
  5.  *  
  6.  * @author andy 
  7.  * @version 2.2 
  8.  */  
  9.   
  10. public class MybatisRedisCache implements Cache {  
  11.   
  12.     private static final Logger LOG = Logger.getLogger(MybatisRedisCache.class);   
  13.       
  14.     private final ReadWriteLock readWriteLock = new ReentrantReadWriteLock(true);  
  15.       
  16.     private RedisTemplate<Serializable, Serializable> redisTemplate =  (RedisTemplate<Serializable, Serializable>) SpringContextHolder.getBean("redisTemplate");   
  17.       
  18.     private String id;  
  19.       
  20.     private JdkSerializationRedisSerializer jdkSerializer = new JdkSerializationRedisSerializer();  
  21.       
  22.     public MybatisRedisCache(final String id){  
  23.         if(id == null){  
  24.             throw new IllegalArgumentException("Cache instances require an ID");  
  25.         }  
  26.         LOG.info("Redis Cache id " + id);  
  27.         this.id = id;  
  28.     }  
  29.       
  30.     @Override  
  31.     public String getId() {  
  32.         return this.id;  
  33.     }  
  34.   
  35.     @Override  
  36.     public void putObject(Object key, Object value) {  
  37.         if(value != null){  
  38.             redisTemplate.opsForValue().set(key.toString(), jdkSerializer.serialize(value), 2, TimeUnit.DAYS);  
  39.         }  
  40.     }  
  41.   
  42.     @Override  
  43.     public Object getObject(Object key) {  
  44.         try {  
  45.             if(key != null){  
  46.                 Object obj = redisTemplate.opsForValue().get(key.toString());  
  47.                 return jdkSerializer.deserialize((byte[])obj);   
  48.             }  
  49.         } catch (Exception e) {  
  50.             LOG.error("redis ");  
  51.         }  
  52.         return null;  
  53.     }  
  54.   
  55.     @Override  
  56.     public Object removeObject(Object key) {  
  57.         try {  
  58.             if(key != null){  
  59.                 redisTemplate.expire(key.toString(), 1, TimeUnit.SECONDS);  
  60.             }  
  61.         } catch (Exception e) {  
  62.         }  
  63.         return null;  
  64.     }  
  65.   
  66.     @Override  
  67.     public void clear() {  
  68.         //jedis nonsupport  
  69.     }  
  70.   
  71.     @Override  
  72.     public int getSize() {  
  73.         Long size = redisTemplate.getMasterRedisTemplate().execute(new RedisCallback<Long>(){  
  74.             @Override  
  75.             public Long doInRedis(RedisConnection connection)  
  76.                     throws DataAccessException {  
  77.                 return connection.dbSize();  
  78.             }  
  79.         });  
  80.         return size.intValue();  
  81.     }  
  82.   
  83.     @Override  
  84.     public ReadWriteLock getReadWriteLock() {  
  85.         return this.readWriteLock;  
  86.     }  
  87.       
  88. }  

3、二级缓存的实用

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

      

  1.   <cache  
  2.     type="org.andy.shop.cache.MybatisRedisCache"  
  3. eviction="LRU"  
  4. flushInterval="6000000"  
  5. size="1024"  
  6. readOnly="false"  
  7. />  


4、Redis中的存储

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

    



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值