使用redis做mybaties的二级缓存(1)
前言
1.环境: spring3.2.4+jedis2.7.2+redis服务3.0.7+mybaties3.2.4
正文
1.mybatis-config.xml开启二级缓存
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration> <settings> <!-- 这个配置使全局的映射器启用或禁用缓存 --> <setting name="cacheEnabled" value="true" /> <!-- 对于未知的SQL查询,允许返回不同的结果集以达到通用的效果 --> <setting name="multipleResultSetsEnabled" value="true" /> <!-- 配置默认的执行器。SIMPLE 执行器没有什么特别之处。REUSE 执行器重用预处理语句。BATCH 执行器重用语句和批量更新 --> <setting name="defaultExecutorType" value="REUSE" /> <!-- 全局启用或禁用延迟加载。当禁用时,所有关联对象都会即时加载。 --> <setting name="lazyLoadingEnabled" value="false" /> <setting name="aggressiveLazyLoading" value="true" /> <!-- <setting name="enhancementEnabled" value="true"/> --> <!-- 设置超时时间,它决定驱动等待一个数据库响应的时间。 --> <setting name="defaultStatementTimeout" value="25000" /> <setting name="logImpl" value="STDOUT_LOGGING" /> </settings> <mappers> <mapper resource="lq/User.xml"/> <mapper resource="lq/redis/cache/Role.xml"/> <mapper resource="lq/redis/cache/Resc.xml"/> </mappers> </configuration>
2.Resc.xml
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="lq.redis.cache.RescMapper"> <!-- redis缓存 --> <cache eviction="LRU" type="lq.redis.cache.RedisCache" /> <select id="getResc" parameterType="lq.redis.cache.Resc" resultType="lq.redis.cache.Resc" useCache="true"> SELECT id,NAME,res_type,res_string,priority,descn FROM resc WHERE id=#{id} </select> <select id="getRescPageList" parameterType="lq.redis.cache.Resc" resultType="lq.redis.cache.Resc" useCache="true"> SELECT id,NAME,res_type,res_string,priority,descn FROM resc </select> <select id="getRescPageCount" parameterType="lq.redis.cache.Resc" resultType="String" useCache="true"> SELECT count(id) FROM resc </select> <insert id="addResc" parameterType="lq.redis.cache.Resc" flushCache="true"> INSERT INTO resc (id,NAME,res_type,res_string,priority,descn) VALUES ( #{id},#{NAME},#{res_type},#{res_string},#{priority},#{descn} ) </insert> <update id="updateResc" parameterType="lq.redis.cache.Resc" flushCache="true" > update resc set NAME= #{name} where id=#{id} </update> <delete id="delResc" parameterType="lq.redis.cache.Resc" flushCache="true"> DELETE FROM resc WHERE id=#{id} </delete> <select id="getRescAndRole" parameterType="lq.redis.cache.RescRole" resultType="lq.redis.cache.RescRole" useCache="true"> SELECT resc.id,resc.NAME,resc.res_type,resc.res_string,resc.priority,resc.descn ,role.NAME AS roleName FROM resc LEFT JOIN resc_role ON resc.id=resc_role.resc_id LEFT JOIN role ON resc_role.role_id=role.id </select> </mapper>
1.<cache>,
2.flushCache="true"
3.useCache="true"
4.getRescAndRole,多表查询最好别用缓存,理由 http://www.cnblogs.com/crazylqy/p/5983507.html
3.RedisCache
package lq.redis.cache; import java.util.Iterator; import java.util.Set; import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock; import lq.redis.IbatisRedisClient; import lq.util.SpringUtil; import org.apache.ibatis.cache.Cache; import org.apache.ibatis.cache.CacheKey; import org.apache.ibatis.logging.Log; import org.apache.ibatis.logging.LogFactory; import redis.clients.jedis.Jedis; public class RedisCache implements Cache { private static Log logger = LogFactory.getLog(RedisCache.class); /** The ReadWriteLock. */ private final ReadWriteLock readWriteLock = new ReentrantReadWriteLock(); private String id; public RedisCache(final String id) { if (id == null) { throw new IllegalArgumentException("Cache instances require an ID"); } logger.debug(">>>>>>>>>>>>>>>>>>>>>>>>MybatisRedisCache:id=" + id); this.id = id; } public String getId() { return this.id; } public int getSize() { IbatisRedisClient ibatisRedisClientImpl=(IbatisRedisClient)SpringUtil.getObject("ibatisRedisClient"); Jedis jedis = ibatisRedisClientImpl.getResource(); try{ return Integer.valueOf(jedis.dbSize().toString()); }finally{ ibatisRedisClientImpl.returnResource(jedis); } } public void putObject(Object key, Object value) { IbatisRedisClient ibatisRedisClientImpl=(IbatisRedisClient)SpringUtil.getObject("ibatisRedisClient"); Jedis jedis = ibatisRedisClientImpl.getResource(); try{ logger.debug(">>>>>>>>>>>>>>>>>>>>>>>>putObject:" + key + "=" + value); byte[] keyByte=SerializeUtil.serialize(key.toString()); byte[] valyeByte=SerializeUtil.serialize(value); // jedis.set(keyByte,valyeByte); jedis.hset(id.getBytes(), keyByte, valyeByte); } catch (Exception e) { e.printStackTrace(); }finally{ ibatisRedisClientImpl.returnResource(jedis); } } public Object getObject(Object key) { CacheKey ck=(CacheKey)key; IbatisRedisClient ibatisRedisClientImpl=(IbatisRedisClient)SpringUtil.getObject("ibatisRedisClient"); Jedis jedis = ibatisRedisClientImpl.getResource(); try{ byte[] keyByte=SerializeUtil.serialize(key.toString()); //byte[] valyeByte=jedis.get(keyByte); byte[] valyeByte=jedis.hget(id.getBytes(), keyByte); Object value = null; if(valyeByte!=null){ value=SerializeUtil.unserialize(valyeByte); } logger.debug(">>>>>>>>>>>>>>>>>>>>>>>>getObject:" + key + "=" + value); return value; } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); }finally{ ibatisRedisClientImpl.returnResource(jedis); } return null; } public Object removeObject(Object key) { IbatisRedisClient ibatisRedisClientImpl=(IbatisRedisClient)SpringUtil.getObject("ibatisRedisClient"); Jedis jedis = ibatisRedisClientImpl.getResource(); try{ return jedis.expire(SerializeUtil.serialize(key.toString()), 0); }finally{ ibatisRedisClientImpl.returnResource(jedis); } } public void clear() { IbatisRedisClient ibatisRedisClientImpl=(IbatisRedisClient)SpringUtil.getObject("ibatisRedisClient"); Jedis jedis = ibatisRedisClientImpl.getResource(); try{ //jedis.flushDB(); //jedis.hdel(key, fields); Set<byte[]> set=jedis.hkeys(id.getBytes()); Iterator<byte[]> it=set.iterator(); while(it.hasNext()){ byte[] field=it.next(); jedis.hdel(id.getBytes(), field); } }finally{ ibatisRedisClientImpl.returnResource(jedis); } } public ReadWriteLock getReadWriteLock() { return readWriteLock; } }
4.序列化类
package lq.redis.cache; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class SerializeUtil { protected static final Logger log = LoggerFactory.getLogger(SerializeUtil.class); public static byte[] serialize2(Object object) throws Exception { ObjectOutputStream oos = null; ByteArrayOutputStream baos = null; // 序列化 baos = new ByteArrayOutputStream(); oos = new ObjectOutputStream(baos); oos.writeObject(object); byte[] bytes = baos.toByteArray(); baos.flush(); baos.close(); return bytes; } public static Object unserialize2(byte[] bytes) throws Exception { ByteArrayInputStream bais = new ByteArrayInputStream(bytes); // 反序列化 ObjectInputStream ois = new ObjectInputStream(bais); Object result = ois.readObject(); ois.close(); return result; } public static Object unserialize(byte[] bytes) { Object object = null; ByteArrayInputStream bais = null; ObjectInputStream ois = null; try { bais = new ByteArrayInputStream(bytes); ois = new ObjectInputStream(bais); object = ois.readObject(); return object; } catch (Exception e) { log.error(e.getMessage(), e); } finally { if (ois != null) { try { ois.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } if (bais != null) { try { bais.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } return null; } public static byte[] serialize(Object obj) { ByteArrayOutputStream bos = null; ObjectOutputStream oos =null;; try { bos = new ByteArrayOutputStream(); oos = new ObjectOutputStream(bos); oos.writeObject(obj); oos.flush(); return bos.toByteArray(); } catch (IOException e) { // TODO Auto-generated catch block log.error(e.getMessage(), e); }finally{ if(oos!=null){ try { oos.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } if(bos!=null){ try { bos.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } return null; } }
5.测试类
package lq.redis.cache; import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; @Controller @RequestMapping("resc") public class RescConstroller { @Autowired private RescMapper rescMapper; @RequestMapping("getResc.do") @ResponseBody public void getResc(String id){ Resc Resc=new Resc(); Resc.setId(id); Resc resRole=rescMapper.getResc(Resc); System.out.println(resRole.getNAME()); } @RequestMapping("getRescPageList.do") @ResponseBody public void getRescPageList(){ Resc Resc=new Resc(); List<Resc> roleList=rescMapper.getRescPageList(Resc); System.out.println(roleList.size()); } @RequestMapping("getRescPageCount.do") @ResponseBody public void getRescPageCount(){ Resc Resc=new Resc(); String count=rescMapper.getRescPageCount(Resc); System.out.println(count); } @RequestMapping("addResc.do") @ResponseBody public void addResc(){ Resc Resc=new Resc(); Resc.setId("5"); Resc.setNAME("test"); Resc.setDescn("testtest"); Resc.setPriority("11"); Resc.setRes_string("111"); Resc.setRes_type("111"); rescMapper.addResc(Resc); System.out.println(Resc.getNAME()); } @RequestMapping("updateResc.do") @ResponseBody public void updateResc(){ Resc Resc=new Resc(); Resc.setId("3"); Resc.setNAME("testtest"); rescMapper.updateResc(Resc); System.out.println(Resc.getNAME()); } @RequestMapping("delResc.do") @ResponseBody public void delResc(){ Resc Resc=new Resc(); Resc.setId("4"); rescMapper.delResc(Resc); System.out.println(Resc.getNAME()); } @RequestMapping("getRescAndRole.do") @ResponseBody public void getRescAndRole(){ RescRole rescRole=new RescRole(); List<RescRole> roleList=rescMapper.getRescAndRole(rescRole); for(RescRole temp:roleList){ System.out.println(temp.getNAME()+":"+temp.getRoleName()); } } }
1.执行查询语句时候丢进缓存,第二次查询相同语句直接在缓存中取,执行insert,update,del语句刷新该工作空间缓存
2.假如执行getRescAndRole,缓存了role表和resc的数据,role表f更新时候时候因为getRescAndRole在resc的工作空间(执行resc的ddl操作会更新缓存因为(getRescAndRole在空做空间lq.redis.cache.RescMapper)),所以缓存没没有刷新,导致过期数据,所以
多表跨工作空间要慎重使用
3.多表时候缓存把表放在同一个工作空间 ,获取更新role时候以原数据更新一下resc达到清理缓存目的