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、配置文件中開啟二級緩存

 

[html] view plain copy 在CODE上查看代碼片派生到我的代碼片
  1. <setting name="cacheEnabled" value="true"/>  


   默認二級緩存是開啟的。

2、實現Mybatis的Cache接口

     Mybatis提供了第三方Cache實現的接口,我們自定義MybatisRedisCache實現Cache接口,代碼如下:

[java] view plain copy 在CODE上查看代碼片派生到我的代碼片
  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功能。

      

[html] view plain copy 在CODE上查看代碼片派生到我的代碼片
  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中的二級緩存。其查詢結果如下:

    


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM