看过市面上其他人写的相关的文章,基本上都是没有深入思考与实际使用的。
大都问题是clear()的时候将整个redisDB全部删除了,而没有做到只将单前某个mapper对应的缓存删除。
package com.west.lake.blog.foundation;
import com.west.lake.blog.model.RedisKeySet;
import com.west.lake.blog.model.SystemConfig;
import com.west.lake.blog.tools.SpringTools;
import org.apache.ibatis.cache.Cache;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
/**
* 使用redis作为mybatis的二级缓存
* <p>
* 规则:
* 以mapper为单位进行存储,前缀为mybatis.${MapperDao}.****。
* 所以删除的时候也以mapper为单位进行删除。
* 对于删除:
* 1.思路:先根据前缀通过keys操作获取keyList。==>因为redis是单线程的,所以不允许使用keys操作,会阻塞其他的线程获取redis操作。(可以考虑使用scan操作)
* 2.思路:先将所有的mybatis二级缓存的key根据mapper进行分组存入redis的每个list中,删除的时候先从redis的list中获取对应mapper的所有的key
*
* @author futao
* Created on 2019-03-06.
*/
@SuppressWarnings("unchecked")
public class MybatisCacheRedis implements Cache {
private static final Logger logger = LoggerFactory.getLogger(MybatisCacheRedis.class);
private final ReadWriteLock readWriteLock = new ReentrantReadWriteLock();
/**
* cache instance id
*/
private final String id;
private RedisTemplate redisTemplate;
/**
* redis过期时间
*/
private static final long EXPIRE_TIME_IN_MINUTES = SystemConfig.MYBATIS_CACHE_REDIS_SECOND;
public MybatisCacheRedis(String id) {
if (id == null) {
throw new IllegalArgumentException("Cache instances require an ID");
}
this.id = id;
}
@Override
public String getId() {
return id;
}
/**
* Put query result to redis
*
* @param key
* @param value
*/
@Override
public void putObject(Object key, Object value) {
if (key != null && value != null) {
RedisTemplate redisTemplate = getRedisTemplate();
String redisKey = RedisKeySet.Mybatis.mybatisSecondCacheMapperKey(id + ":" + key);
//不要设置过期时间
redisTemplate.opsForList().rightPush(RedisKeySet.Mybatis.mybatisSecondCacheListKey(id), redisKey);
redisTemplate.opsForValue().set(redisKey, value, EXPIRE_TIME_IN_MINUTES, TimeUnit.SECONDS);
logger.info("\n<<< 结果插入redis缓存\n【key】{}\n【值】:{}", redisKey, value);
}
}
/**
* Get cached query result from redis
*
* @param key
* @return
*/
@Override
public Object getObject(Object key) {
RedisTemplate redisTemplate = getRedisTemplate();
ValueOperations opsForValue = redisTemplate.opsForValue();
String redisKey = RedisKeySet.Mybatis.mybatisSecondCacheMapperKey(id + ":" + key);
Object result = opsForValue.get(redisKey);
logger.info("\n<<< 从redis中查询缓存\n【key】{}\n【结果】:{}", redisKey, result);
return result;
}
/**
* Remove cached query result from redis
*
* @param key
* @return
*/
@Override
public Object removeObject(Object key) {
RedisTemplate redisTemplate = getRedisTemplate();
String redisKey = RedisKeySet.Mybatis.mybatisSecondCacheMapperKey(id + ":" + key);
logger.info("\n<<< 从redis中移除缓存\n【key】{}", redisKey);
//TODO(...)
return redisTemplate.delete(redisKey);
}
/**
* delete
* Clears this cache instance
*/
@Override
public void clear() {
RedisTemplate redisTemplate = getRedisTemplate();
// redisTemplate.execute((RedisCallback) connection -> {
//// connection.flushDb();
//// return null;
//// });
String key = RedisKeySet.Mybatis.mybatisSecondCacheListKey(id);
//从mapper list中获取mapper keys
List range = redisTemplate.opsForList().range(key, 0, -1);
//删除mapper list
range.add(key);
//删除mapper kv
Long delete = redisTemplate.delete(range);
logger.info("\n<<< 删除redis中【{}】的缓存\n删除条数【{}】", key, delete);
}
@Override
public int getSize() {
return 0;
}
@Override
public ReadWriteLock getReadWriteLock() {
return readWriteLock;
}
private RedisTemplate getRedisTemplate() {
if (redisTemplate == null) {
redisTemplate = SpringTools.getBean("redisTemplate");
}
return redisTemplate;
}
}
网友评论