一、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、設定檔中開啟二級緩衝
<setting name="cacheEnabled" value="true"/>
預設二級緩衝是開啟的。
2、實現Mybatis的Cache介面
Mybatis提供了第三方Cache實現的介面,我們自訂MybatisRedisCache實現Cache介面,代碼如下:
/** * 建立時間:2016年1月7日 上午11:40:00 * * Mybatis二級緩衝實作類別 * * @author andy * @version 2.2 */public class MybatisRedisCache implements Cache {private static final Logger LOG = Logger.getLogger(MybatisRedisCache.class); private final ReadWriteLock readWriteLock = new ReentrantReadWriteLock(true);private RedisTemplate<Serializable, Serializable> redisTemplate = (RedisTemplate<Serializable, Serializable>) SpringContextHolder.getBean("redisTemplate"); private String id;private JdkSerializationRedisSerializer jdkSerializer = new JdkSerializationRedisSerializer();public MybatisRedisCache(final String id){if(id == null){throw new IllegalArgumentException("Cache instances require an ID");}LOG.info("Redis Cache id " + id);this.id = id;}@Overridepublic String getId() {return this.id;}@Overridepublic void putObject(Object key, Object value) {if(value != null){redisTemplate.opsForValue().set(key.toString(), jdkSerializer.serialize(value), 2, TimeUnit.DAYS);}}@Overridepublic Object getObject(Object key) {try {if(key != null){Object obj = redisTemplate.opsForValue().get(key.toString());return jdkSerializer.deserialize((byte[])obj); }} catch (Exception e) {LOG.error("redis ");}return null;}@Overridepublic Object removeObject(Object key) {try {if(key != null){redisTemplate.expire(key.toString(), 1, TimeUnit.SECONDS);}} catch (Exception e) {}return null;}@Overridepublic void clear() {//jedis nonsupport}@Overridepublic int getSize() {Long size = redisTemplate.getMasterRedisTemplate().execute(new RedisCallback<Long>(){@Overridepublic Long doInRedis(RedisConnection connection)throws DataAccessException {return connection.dbSize();}});return size.intValue();}@Overridepublic ReadWriteLock getReadWriteLock() {return this.readWriteLock;}}
3、二級緩衝的實用
我們需要將所有的實體類進行序列化,然後在Mapper中添加自訂cache功能。
<cache type="org.andy.shop.cache.MybatisRedisCache"eviction="LRU"flushInterval="6000000"size="1024"readOnly="false"/>
4、Redis中的儲存
redis會自動的將Sql+條件+Hash等當做key值,而將查詢結果作為value,只有請求中的所有參數都符合,那麼就會使用redis中的二級緩衝。其查詢結果如下: