今天在公司里有个大佬给我一个缓存的方向,就是用mybatis的Cache接口类似于这种
package com.hua.redis; import java.util.Map; 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 org.springframework.data.redis.connection.RedisConnection; import org.springframework.data.redis.core.HashOperations; import org.springframework.data.redis.core.RedisCallback; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.serializer.RedisSerializer; import org.springframework.util.StringUtils; public class RedisCache implements Cache { private static final Logger LOG = LoggerFactory.getLogger(RedisCache.class); private final ReadWriteLock readWriteLock = new ReentrantReadWriteLock(); private final String id; // cache instance id private RedisTemplate<?, ?> redisTemplate; public RedisCache(String id) { if (id == null) { throw new IllegalArgumentException("Cache instances require an ID"); } this.id = id; } /** * @return string */ @Override public String getId() { return id; } /** * @return int */ @Override public int getSize() { RedisTemplate<?, ?> redisTemplate = getRedisTemplate(); redisTemplate.setKeySerializer(redisTemplate.getStringSerializer()); HashOperations hashOperations = redisTemplate.opsForHash(); Map map = hashOperations.entries(id); LOG.error("RedisCache getSize>>>id:>>" + id); if(map != null && !map.isEmpty()) { return map.size(); } else { return 0; } } /** * Put query result to redis * * @param key * @param value */ @Override public void putObject(Object key, Object value) { RedisTemplate<?, ?> redisTemplate = getRedisTemplate(); redisTemplate.setKeySerializer(redisTemplate.getStringSerializer()); HashOperations hashOperations = redisTemplate.opsForHash(); // ValueOperations opsForValue = redisTemplate.opsForValue(); if (key == null) { LOG.error("RedisCache putObject>>>id:>>" + id+">key>>"+key); } try { //增加空判断,如果查询结果为空,不插入缓存 if(value == null || (value instanceof String && StringUtils.isEmpty((String) value))) { LOG.error("RedisCache putObject>>>id:>>" + id+">key>>"+key); return; } LOG.info("RedisCache putObject>>>id:>>" + id+">key>>"+key); hashOperations.put(id, key, value); } catch (Exception e) { LOG.error(e.getMessage()); } } /** * Get cached query result from redis * * @param key * @return */ @Override public Object getObject(Object key) { RedisTemplate<?, ?> redisTemplate = getRedisTemplate(); redisTemplate.setKeySerializer(redisTemplate.getStringSerializer()); // ValueOperations<?, ?> opsForValue = redisTemplate.opsForValue(); HashOperations hashOperations = redisTemplate.opsForHash(); LOG.info("Get cached query result from redis id>>"+id+">key>>"+key); // return opsForValue.get(key); return hashOperations.get(id, key); } /** * Remove cached query result from redis * * @param key * @return */ @Override public Object removeObject(Object key) { RedisTemplate redisTemplate = getRedisTemplate(); redisTemplate.setKeySerializer(redisTemplate.getStringSerializer()); HashOperations hashOperations = redisTemplate.opsForHash(); if (key == null) { LOG.error("RedisCache removeObject>>>id:>>" + id+">key>>"+key); } hashOperations.delete(id, key); LOG.info("Remove cached query result from redis>>"+id+">>"+key); return null; } /** * Clears this cache instance */ @Override public void clear() { RedisTemplate<?, ?> redisTemplate = getRedisTemplate(); redisTemplate.setKeySerializer(redisTemplate.getStringSerializer()); final RedisSerializer<String> redisSerializer = redisTemplate.getStringSerializer(); redisTemplate.execute(new RedisCallback<String>() { public String doInRedis(RedisConnection conn) { byte[] keyByte = redisSerializer.serialize(id); conn.del(keyByte); LOG.info("clear cached query result from redis"+id); return "successful"; } }); } /** * @return ReadWriteLock */ @Override public ReadWriteLock getReadWriteLock() { return readWriteLock; } /** * @return RedisTemplate<String, String> */ private RedisTemplate<?, ?> getRedisTemplate() { if (redisTemplate == null) { redisTemplate = ApplicationContextHolder.getBean("redisTemplate"); } return redisTemplate; } }
大致的意思就是在mybatis中
<select>标签会去缓存sql的结构,以namespace+sql+param的为key有就拿缓存没有就读db放缓存
<update><delete>这种的清除缓存
不用人为的去干预缓存的管理,避免造成一方去cache了但是有业务update忘记去清除缓存而有脏数据的尴尬
我用这个思路去找了下jfinal中有无类似的东西,发现activerecode中有一个ICache,但是这个接口稍微有点远离实际环境,原因有几点
在Model类中只去cache.put,在udpate和delete时候remove和removeAll并没有去调用(可能我看漏了,但是在Model中确实只有put没有清除缓存的相关逻辑)
在做findByCache的时候需要去传一个sql,这个我感觉完全可以做成拿activerecord帮我去生成的sql和我findByCache带的参数和我的Model class name来拼接一个Key,如果人为的去传sql虽然说更加自由,但是我感觉大多情况如果用activerecode的话就是不想写sql,传了sql等于去管理cache key, 一下子复杂度就上去了,我还要去管理我的key,我不知道当初这么设计是为了让开发更自由还是什么原因
我不知道以后jfianl能否提供一个和mybatis类似的,在我crud的时候一个统一的Cache接口,我只需要去关注我key value的存储到哪里去了,而不需要关心我什么时候去put我什么时候去remove
项目:JFinal