0. 相关知识:
查询缓存:绝大数系统主要是读多写少。
缓存作用:减轻数据库压力,提供访问速度。
  
1. 一级缓存测试用例
(1) 默认开启,不需要有什么配置
(2) 示意图

 
(3) 测试代码
- package com.sohu.tv.cache;  
 
- import org.apache.ibatis.session.SqlSession;  
 
- import org.junit.After;  
 
- import org.junit.Before;  
 
- import org.junit.Test;  
 
- import com.sohu.tv.bean.Player;  
 
- import com.sohu.tv.mapper.PlayerDao;  
 
- import com.sohu.tv.test.mapper.BaseTest;  
 
- public class FirstCacheTest extends BaseTest {  
 
-     private SqlSession sqlSession;  
 
-     private SqlSession sqlSessionAnother;  
 
-   
 
-       
 
-     @Before  
 
-     public void before() {  
 
-         sqlSession = sessionFactory.openSession(false);  
 
-         sqlSessionAnother = sessionFactory.openSession(false);  
 
-     }  
 
-     @After  
 
-     public void after() {  
 
-         sqlSession.close();  
 
-         sqlSessionAnother.close();  
 
-     }  
 
-     @Test  
 
-     public void test1() throws Exception {  
 
-         PlayerDao playerDao = sqlSession.getMapper(PlayerDao.class);  
 
-         Player player = playerDao.getPlayerById(1);  
 
-         System.out.println(player);  
 
-           
 
-         playerDao = sqlSession.getMapper(PlayerDao.class);  
 
-         player = playerDao.getPlayerById(1);  
 
-         System.out.println(player);  
 
-           
 
-         playerDao = sqlSessionAnother.getMapper(PlayerDao.class);  
 
-         player = playerDao.getPlayerById(1);  
 
-         System.out.println(player);  
 
-           
 
-     }  
 
-       
 
-     @Test  
 
-     public void test2() throws Exception {  
 
-         PlayerDao playerDao = sqlSession.getMapper(PlayerDao.class);  
 
-         Player player = playerDao.getPlayerById(1);  
 
-         System.out.println(player);  
 
-           
 
-         
 
-           
 
-         
 
-         playerDao.deletePlayer(4);  
 
-           
 
-         player = playerDao.getPlayerById(1);  
 
-         System.out.println(player);  
 
-           
 
-     }  
 
-       
 
-       
 
- }  
 
 
 
2、二级缓存(自带 PerpetualCache)
(0) 示意图

 
(1) 二级缓存需要开启
总配置文件中,二级缓存也是开启的,不需要设置
- <setting name="cacheEnabled" value="true"/>  
 
 
mapper级别的cache需要开启,在对应的mapper.xml写入
(2) 实体类在二级缓存中需要进行序列化,所以所有实体类需要实现Serializable 
(3) 示例:
- package com.sohu.tv.cache;  
 
- import org.apache.ibatis.session.SqlSession;  
 
- import org.junit.After;  
 
- import org.junit.Before;  
 
- import org.junit.Test;  
 
- import com.sohu.tv.bean.Player;  
 
- import com.sohu.tv.mapper.PlayerDao;  
 
- import com.sohu.tv.test.mapper.BaseTest;  
 
- public class SecondCacheTest extends BaseTest {  
 
-     private SqlSession sqlSession1 = sessionFactory.openSession();  
 
-       
 
-     private SqlSession sqlSession2 = sessionFactory.openSession();  
 
-       
 
-     private SqlSession sqlSession3 = sessionFactory.openSession();  
 
-       
 
-     private PlayerDao playerDao1;  
 
-       
 
-     private PlayerDao playerDao2;  
 
-       
 
-     private PlayerDao playerDao3;  
 
-       
 
-     @Before  
 
-     public void before() {  
 
-         sqlSession1 = sessionFactory.openSession(false);  
 
-         sqlSession2 = sessionFactory.openSession(false);  
 
-         sqlSession3 = sessionFactory.openSession(false);  
 
-           
 
-         playerDao1 = sqlSession1.getMapper(PlayerDao.class);  
 
-         playerDao2 = sqlSession2.getMapper(PlayerDao.class);  
 
-         playerDao3 = sqlSession3.getMapper(PlayerDao.class);  
 
-     }  
 
-     @After  
 
-     public void after() {  
 
-         sqlSession1.close();  
 
-         sqlSession2.close();  
 
-         sqlSession3.close();  
 
-     }  
 
-        
 
-     @Test  
 
-     public void test1() throws Exception {  
 
-         int targetId = 1;  
 
-           
 
-         
 
-         Player player1 = playerDao1.getPlayerById(targetId);  
 
-         System.out.println("player1: " + player1);  
 
-         sqlSession1.commit();  
 
-           
 
-         
 
-         Player player2 = playerDao2.getPlayerById(targetId);  
 
-         System.out.println("player2: " + player2);  
 
-         player2.setAge(15);  
 
-         playerDao2.update(player2);  
 
-         sqlSession2.commit();  
 
-           
 
-         
 
-         Player player3 = playerDao3.getPlayerById(targetId);  
 
-         System.out.println("player3: " + player3);  
 
-     }  
 
-       
 
-     @Test  
 
-     public void test2() throws Exception {  
 
-         int one = 1;  
 
-         int two = 2;  
 
-           
 
-         
 
-         Player player1 = playerDao1.getPlayerById(one);  
 
-         playerDao1.getPlayerById(two);  
 
-         System.out.println("player1: " + player1);  
 
-         sqlSession1.commit();  
 
-           
 
-         
 
-         Player player2 = playerDao2.getPlayerById(one);  
 
-         System.out.println("player2: " + player2);  
 
-         player2.setAge(15);  
 
-         playerDao2.updatePlayer(player2);  
 
-         sqlSession2.commit();  
 
-           
 
-         
 
-         Player player3 = playerDao3.getPlayerById(two);  
 
-         System.out.println("player3: " + player3);  
 
-     }  
 
-       
 
-       
 
- }  
 
 
(4) 重要日志:
 
3、二级缓存(Redis版)
(1) redis使用一个简单的单点实例作为数据源:
引入jedis pom依赖:
- <jedis.version>2.8.0</jedis.version>  
 
- <protostuff.version>1.0.8</protostuff.version>  
 
- <dependency>  
 
-     <groupId>redis.clients</groupId>  
 
-     <artifactId>jedis</artifactId>  
 
-     <version>${jedis.version}</version>  
 
- </dependency>  
 
- <dependency>  
 
-     <groupId>com.dyuproject.protostuff</groupId>  
 
-     <artifactId>protostuff-runtime</artifactId>  
 
-     <version>${protostuff.version}</version>  
 
- </dependency>  
 
-   
 
- <dependency>  
 
-     <groupId>com.dyuproject.protostuff</groupId>  
 
-     <artifactId>protostuff-core</artifactId>  
 
-     <version>${protostuff.version}</version>  
 
- </dependency>  
 
 
 
jedis获取工具(使用jedispool)
- package com.sohu.tv.redis;  
 
- import org.apache.commons.pool2.impl.GenericObjectPoolConfig;  
 
- import org.slf4j.Logger;  
 
- import org.slf4j.LoggerFactory;  
 
- import redis.clients.jedis.JedisPool;  
 
- public class RedisStandAloneUtil {  
 
-     private final static Logger logger = LoggerFactory.getLogger(RedisStandAloneUtil.class);  
 
-     
 
-     private static JedisPool jedisPool;  
 
-        
 
-     
 
-     private final static String REDIS_HOST = "10.10.xx.xx";  
 
-        
 
-     
 
-     private final static int REDIS_PORT = 6384;  
 
-        
 
-     static {  
 
-         try {  
 
-             jedisPool = new JedisPool(new GenericObjectPoolConfig(), REDIS_HOST, REDIS_PORT);  
 
-         } catch (Exception e) {  
 
-             logger.error(e.getMessage(), e);  
 
-         }  
 
-     }  
 
-     public static JedisPool getJedisPool() {  
 
-         return jedisPool;  
 
-     }  
 
-         
 
-     public static void main(String[] args) {  
 
-         System.out.println(RedisStandAloneUtil.getJedisPool().getResource().info());  
 
-     }  
 
- }  
 
 
 
(2) 如果自己实现mybatis的二级缓存,需要实现org.apache.ibatis.cache.Cache接口,已经实现的有如下:

 
 
序列化相关工具代码:
- package com.sohu.tv.redis.serializable;  
 
-   
 
-   
 
-   
 
- import com.dyuproject.protostuff.LinkedBuffer;  
 
- import com.dyuproject.protostuff.ProtostuffIOUtil;  
 
- import com.dyuproject.protostuff.Schema;  
 
- import com.dyuproject.protostuff.runtime.RuntimeSchema;  
 
-   
 
- import java.util.concurrent.ConcurrentHashMap;  
 
-   
 
- public class ProtostuffSerializer {  
 
-   
 
-     private static ConcurrentHashMap<Class<?>, Schema<?>> cachedSchema = new ConcurrentHashMap<Class<?>, Schema<?>>();  
 
-   
 
-     public <T> byte[] serialize(final T source) {  
 
-         VO<T> vo = new VO<T>(source);  
 
-   
 
-         final LinkedBuffer buffer = LinkedBuffer.allocate(LinkedBuffer.DEFAULT_BUFFER_SIZE);  
 
-         try {  
 
-             final Schema<VO> schema = getSchema(VO.class);  
 
-             return serializeInternal(vo, schema, buffer);  
 
-         } catch (final Exception e) {  
 
-             throw new IllegalStateException(e.getMessage(), e);  
 
-         } finally {  
 
-             buffer.clear();  
 
-         }  
 
-     }  
 
-   
 
-     public <T> T deserialize(final byte[] bytes) {  
 
-         try {  
 
-             Schema<VO> schema = getSchema(VO.class);  
 
-             VO vo = deserializeInternal(bytes, schema.newMessage(), schema);  
 
-             if (vo != null && vo.getValue() != null) {  
 
-                 return (T) vo.getValue();  
 
-             }  
 
-         } catch (final Exception e) {  
 
-             throw new IllegalStateException(e.getMessage(), e);  
 
-         }  
 
-         return null;  
 
-     }  
 
-   
 
-     private <T> byte[] serializeInternal(final T source, final Schema<T> schema, final LinkedBuffer buffer) {  
 
-         return ProtostuffIOUtil.toByteArray(source, schema, buffer);  
 
-     }  
 
-   
 
-     private <T> T deserializeInternal(final byte[] bytes, final T result, final Schema<T> schema) {  
 
-         ProtostuffIOUtil.mergeFrom(bytes, result, schema);  
 
-         return result;  
 
-     }  
 
-   
 
-     private static <T> Schema<T> getSchema(Class<T> clazz) {  
 
-         @SuppressWarnings("unchecked")  
 
-         Schema<T> schema = (Schema<T>) cachedSchema.get(clazz);  
 
-         if (schema == null) {  
 
-             schema = RuntimeSchema.createFrom(clazz);  
 
-             cachedSchema.put(clazz, schema);  
 
-         }  
 
-         return schema;  
 
-     }  
 
-   
 
- }  
 
 
 
- package com.sohu.tv.redis.serializable;  
 
-   
 
-   
 
- import java.io.Serializable;  
 
-   
 
- public class VO<T> implements Serializable {  
 
-   
 
-     private T value;  
 
-   
 
-     public VO(T value) {  
 
-         this.value = value;  
 
-     }  
 
-   
 
-     public VO() {  
 
-     }  
 
-   
 
-     public T getValue() {  
 
-         return value;  
 
-     }  
 
-   
 
-     @Override  
 
-     public String toString() {  
 
-         return "VO{" +  
 
-                 "value=" + value +  
 
-                 ‘}‘;  
 
-     }  
 
- }  
 
 
 
 
Redis需要自己来实现,代码如下:
- package com.sohu.tv.redis;  
 
- import java.util.concurrent.locks.ReadWriteLock;  
 
- import java.util.concurrent.locks.ReentrantReadWriteLock;  
 
- import org.apache.ibatis.cache.Cache;  
 
- import org.slf4j.Logger;  
 
- import org.slf4j.LoggerFactory;  
 
- import redis.clients.jedis.Jedis;  
 
- import redis.clients.jedis.serializable.ProtostuffSerializer;  
 
- public class MybatisRedisCache implements Cache {  
 
-     private static Logger logger = LoggerFactory.getLogger(MybatisRedisCache.class);  
 
-     private String id;  
 
-     private final ReadWriteLock readWriteLock = new ReentrantReadWriteLock();  
 
-     private final ProtostuffSerializer protostuffSerializer = new ProtostuffSerializer();  
 
-     public MybatisRedisCache(final String id) {  
 
-         if (logger.isInfoEnabled()) {  
 
-             logger.info("============ MybatisRedisCache id {} ============", id);  
 
-         }  
 
-         if (id == null) {    
 
-             throw new IllegalArgumentException("Cache instances require an ID");    
 
-         }    
 
-         this.id = id;    
 
-     }   
 
-        
 
-     @Override  
 
-     public String getId() {  
 
-         return this.id;  
 
-     }  
 
-     @Override  
 
-     public int getSize() {  
 
-         Jedis jedis = null;  
 
-         int size = -1;  
 
-         try {  
 
-             jedis = RedisStandAloneUtil.getJedisPool().getResource();  
 
-             size = Integer.valueOf(jedis.dbSize().toString());  
 
-         } catch (Exception e) {  
 
-             logger.error(e.getMessage(), e);  
 
-         } finally {  
 
-             if (jedis != null) {  
 
-                 jedis.close();  
 
-             }  
 
-         }  
 
-         return size;  
 
-     }  
 
-     @Override  
 
-     public void putObject(Object key, Object value) {  
 
-         if (logger.isInfoEnabled()) {  
 
-             logger.info("============ putObject key: {}, value: {} ============", key, value);  
 
-         }  
 
-         Jedis jedis = null;  
 
-         try {  
 
-             jedis = RedisStandAloneUtil.getJedisPool().getResource();  
 
-             byte[] byteKey = protostuffSerializer.serialize(key);  
 
-             byte[] byteValue = protostuffSerializer.serialize(value);  
 
-             jedis.set(byteKey, byteValue);  
 
-         } catch (Exception e) {  
 
-             logger.error(e.getMessage(), e);  
 
-         } finally {  
 
-             if (jedis != null) {  
 
-                 jedis.close();  
 
-             }  
 
-         }  
 
-     }  
 
-     @Override  
 
-     public Object getObject(Object key) {  
 
-         if (logger.isInfoEnabled()) {  
 
-             logger.info("============ getObject key: {}============", key);  
 
-         }  
 
-         Object object = null;  
 
-         Jedis jedis = null;  
 
-         try {  
 
-             jedis = RedisStandAloneUtil.getJedisPool().getResource();  
 
-             byte[] bytes = jedis.get(protostuffSerializer.serialize(key));  
 
-             if (bytes != null) {  
 
-                 object = protostuffSerializer.deserialize(bytes);  
 
-             }  
 
-         } catch (Exception e) {  
 
-             logger.error(e.getMessage(), e);  
 
-         } finally {  
 
-             if (jedis != null) {  
 
-                 jedis.close();  
 
-             }  
 
-         }  
 
-         return object;  
 
-     }  
 
-     @Override  
 
-     public Object removeObject(Object key) {  
 
-         if (logger.isInfoEnabled()) {  
 
-             logger.info("============ removeObject key: {}============", key);  
 
-         }  
 
-         String result = "success";  
 
-         Jedis jedis = null;  
 
-         try {  
 
-             jedis = RedisStandAloneUtil.getJedisPool().getResource();  
 
-             jedis.del(String.valueOf(key));  
 
-         } catch (Exception e) {  
 
-             logger.error(e.getMessage(), e);  
 
-         } finally {  
 
-             if (jedis != null) {  
 
-                 jedis.close();  
 
-             }  
 
-         }  
 
-         return result;  
 
-     }  
 
-     @Override  
 
-     public void clear() {  
 
-         if (logger.isInfoEnabled()) {  
 
-             logger.info("============ start clear cache ============");  
 
-         }  
 
-         String result = "fail";  
 
-         Jedis jedis = null;  
 
-         try {  
 
-             jedis = RedisStandAloneUtil.getJedisPool().getResource();  
 
-             result = jedis.flushAll();  
 
-         } catch (Exception e) {  
 
-             logger.error(e.getMessage(), e);  
 
-         } finally {  
 
-             if (jedis != null) {  
 
-                 jedis.close();  
 
-             }  
 
-         }  
 
-         if (logger.isInfoEnabled()) {  
 
-             logger.info("============ end clear cache result is {}============", result);  
 
-         }  
 
-     }  
 
-     @Override  
 
-     public ReadWriteLock getReadWriteLock() {  
 
-         return readWriteLock;  
 
-     }  
 
- }  
 
 
 
(3) mapper配置中加入自定义redis二级缓存:
 
- <cache type="com.sohu.tv.redis.MybatisRedisCache"/>  
 
 
(4) 单元测试同第二节