通大多數(shù)ORM層框架一樣,Mybatis自然也提供了對一級緩存和二級緩存的支持。一下是一級緩存和二級緩存的作用于和定義。
1、一級緩存是Sqlsession級別的緩存。在操作數(shù)據(jù)庫時(shí)需要構(gòu)造 sqlSession對象,在對象中有一個(gè)(內(nèi)存區(qū)域)數(shù)據(jù)結(jié)構(gòu)(HashMap)用于存儲緩存數(shù)據(jù)。不同的sqlSession之間的緩存數(shù)據(jù)區(qū)域(HashMap)是互相不影響的。 二級緩存是mapper級別的緩存,多個(gè)SqlSession去操作同一個(gè)Mapper的sql語句,多個(gè)SqlSession去操作數(shù)據(jù)庫得到數(shù)據(jù)會存在二級緩存區(qū)域,多個(gè)SqlSession可以共用二級緩存,二級緩存是跨SqlSession的。
2、一級緩存的作用域是同一個(gè)SqlSession,在同一個(gè)sqlSession中兩次執(zhí)行相同的sql語句,第一次執(zhí)行完畢會將數(shù)據(jù)庫中查詢的數(shù)據(jù)寫到緩存(內(nèi)存),第二次會從緩存中獲取數(shù)據(jù)將不再從數(shù)據(jù)庫查詢,從而提高查詢效率。當(dāng)一個(gè)sqlSession結(jié)束后該sqlSession中的一級緩存也就不存在了。Mybatis默認(rèn)開啟一級緩存。
二級緩存是多個(gè)SqlSession共享的,其作用域是mapper的同一個(gè)namespace,不同的sqlSession兩次執(zhí)行相同namespace下的sql語句且向sql中傳遞參數(shù)也相同即最終執(zhí)行相同的sql語句,第一次執(zhí)行完畢會將數(shù)據(jù)庫中查詢的數(shù)據(jù)寫到緩存(內(nèi)存),第二次會從緩存中獲取數(shù)據(jù)將不再從數(shù)據(jù)庫查詢,從而提高查詢效率。Mybatis默認(rèn)沒有開啟二級緩存需要在setting全局參數(shù)中配置開啟二級緩存。 一般的我們將Mybatis和sPRing整合時(shí),mybatis-spring包會自動分裝sqlSession,而Spring通過動態(tài)代理sqlSessionProxy使用一個(gè)模板方法封裝了select()等操作,每一次select()查詢都會自動先執(zhí)行openSession(),執(zhí)行完close()以后調(diào)用close()方法,相當(dāng)于生成了一個(gè)新的session實(shí)例,所以我們無需手動的去關(guān)閉這個(gè)session(),當(dāng)然也無法使用mybatis的一級緩存,也就是說mybatis的一級緩存在spring中是沒有作用的。 因此我們一般在項(xiàng)目中實(shí)現(xiàn)Mybatis的二級緩存,雖然Mybatis自帶二級緩存功能,但是如果實(shí)在集群環(huán)境下,使用自帶的二級緩存只是針對單個(gè)的節(jié)點(diǎn),所以我們采用分布式的二級緩存功能。一般的緩存NoSql數(shù)據(jù)庫如Redis,Mancache等,或者EhCache都可以實(shí)現(xiàn),從而更好地服務(wù)tomcat集群中ORM的查詢。
下面主要通過Redis實(shí)現(xiàn)Mybatis的二級緩存功能。
[html] view plain copy 在CODE上查看代碼片派生到我的代碼片
默認(rèn)二級緩存是開啟的。
Mybatis提供了第三方Cache實(shí)現(xiàn)的接口,我們自定義MybatisRedisCache實(shí)現(xiàn)Cache接口,代碼如下:
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; } @Override public String getId() { return this.id; } @Override public void putObject(Object key, Object value) { if(value != null){ redisTemplate.opsForValue().set(key.toString(), jdkSerializer.serialize(value), 2, TimeUnit.DAYS); } } @Override public 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; } @Override public Object removeObject(Object key) { try { if(key != null){ redisTemplate.expire(key.toString(), 1, TimeUnit.SECONDS); } } catch (Exception e) { } return null; } @Override public void clear() { //jedis nonsupport } @Override public int getSize() { Long size = redisTemplate.getMasterRedisTemplate().execute(new RedisCallback<Long>(){ @Override public Long doInRedis(RedisConnection connection) throws DataaccessException { return connection.dbSize(); } }); return size.intValue(); } @Override public ReadWriteLock getReadWriteLock() { return this.readWriteLock; } }我們需要將所有的實(shí)體類進(jìn)行序列化,然后在Mapper中添加自定義cache功能。
<cache type="org.andy.shop.cache.MybatisRedisCache" eviction="LRU" flushInterval="6000000" size="1024" readOnly="false" />redis會自動的將Sql+條件+Hash等當(dāng)做key值,而將查詢結(jié)果作為value,只有請求中的所有參數(shù)都符合,那么就會使用redis中的二級緩存。其查詢結(jié)果如下:
新聞熱點(diǎn)
疑難解答