今天在公司里有个大佬给我一个缓存的方向,就是用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