因为在项目中,会有字典表,机构表,用户表,这些一般情况下,数据发生改变的的概率比较小,而且经常涉及到查询,转码,查询数据库的频率较高,因此在项目启动时将这些数据表加载到缓存中,以便使用。
redis是一种高级的key:value存储系统,其中value支持五种数据类型:
1.字符串(strings)
2.字符串列表(lists)
3.字符串集合(sets)
4.有序字符串集合(sorted sets)
5.哈希(hashes)
1.配置redis jar包
org.springframework.boot
spring-boot-starter-data-redis
2.配置yml文件
redis: database: 2 host: IP地址 port: 6379 password: 1
3.初始化缓存步骤
如果存入redis 的数据量较大,可以采用线程池方式,如果数据量小。可不用
@Configuration
@EnableAsync
public class AsyncConfig {
@Bean
public TaskExecutor taskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
// 设置核心线程数
executor.setCorePoolSize(10);
// 设置最大线程数
executor.setMaxPoolSize(20);
// 设置队列容量
executor.setQueueCapacity(40);
// 设置线程活跃时间(秒)
executor.setKeepAliveSeconds(60);
// 设置默认线程名称
executor.setThreadNamePrefix("async-");
// 设置拒绝策略
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
// 等待所有任务结束后再关闭线程池
executor.setWaitForTasksToCompleteOnShutdown(true);
return executor;
}
}
/**
* 启动加载缓存
*
* @author
*/
@Component
public class InitCache implements ApplicationRunner {
@Autowired
private ICacheService cache;
@Override
@Async
public void run(ApplicationArguments arg) throws Exception {
// 加载字典表缓存
cache.initDictCache();
// 加载表达式缓存
cache.initExpressionCache();
}
}
4.加载字典表缓存
serviceImpl实现类
@Override
public void initDictCache() {
List systemDictList = systemDictMapper.querySystemDictTable();
if (CollectionUtils.isNotEmpty(systemDictList)) {
for (SystemDictTableEntity systemDictTableEntity : systemDictList) {
if (null != systemDictTableEntity) {
if (StringUtils.isNotBlank(systemDictTableEntity.getDictValue())
&& StringUtils.isNotBlank(systemDictTableEntity.getDictKey())) {
RedisUtils.set(RedisKeyPrefix.REDIS_SYSTEM_DICT_KEY + systemDictTableEntity.getDictKey(),
systemDictTableEntity.getDictValue());
}
}
}
}
}
线程池方式加载缓存:
实现类需要注入前面写的线程池的配置类
@Autowired private TaskExecutor taskExecutor;
@Override
public void initExpressionCache() {
long start = System.currentTimeMillis();
log.info("Start Loading Expression into redis cache...");
// 查询表达式全量数据
List expressionCacheDtoList = mapper.getExpression();
// 校验是否有数据需要加载缓存
if (CollectionUtils.isEmpty(expressionCacheDtoList)) {
log.info("There Is Nothing Need To Cache!");
return;
}
// 需要处理的任务总数
int pageCount = expressionCacheDtoList.size();
// 每条线程处理的任务数
int pageSize = 300;
// 计算需要开启多少条线程
int threadCount = pageCount % pageSize == ConstantNumber.ZERO ? pageCount / pageSize
: pageCount / pageSize + ConstantNumber.ONE;
// 开启threadCount条线程
for (int pageNumber = 1; pageNumber <= threadCount; pageNumber++) {
// 计算分页参数
final int executeNumber = pageSize * pageNumber;
taskExecutor.execute(() -> executeCache(expressionCacheDtoList, pageCount, pageSize, executeNumber));
}
// 计算完成任务消耗时间
double cost = (System.currentTimeMillis() - start) / 1000.000;
log.info("Started Loading Expression Cache in {}", cost + " seconds");
}
/**
* 将字段表达式刷入REDIS缓存
*
* @param expressionCacheDtoList
* @param pageCount
* @param pageSize
* @param executeNumber
*/
private void executeCache(List expressionCacheDtoList, int pageCount, int pageSize,
int executeNumber) {
// 校验执行最大数量是否大于总计数
executeNumber = executeNumber < pageCount ? executeNumber : pageCount;
// 声明参数
String expression;
Integer columnId;
Integer expressionTypeId;
StringBuilder sb = new StringBuilder();
// 多线程分页处理
// 例如Thread-1处理0(含)~300(不含),Thread-2处理300~600(不含)
for (int j = executeNumber - pageSize; j < executeNumber; j++) {
ExpressionCacheDto expressionCacheDto = expressionCacheDtoList.get(j);
if (expressionCacheDto != null) {
// 清空StringBuilder
sb.delete(ConstantNumber.ZERO, sb.length());
// 获取字段Value
expression = expressionCacheDto.getExpression();
columnId = expressionCacheDto.getColumnId();
expressionTypeId = expressionCacheDto.getExpressionTypeId();
// 组织RedisKey
sb.append(RedisKeyPrefix.REDIS_EXPRESSION_KEY).append(columnId).append(UNDERLINE)
.append(expressionTypeId);
// 存入缓存
RedisUtils.set(sb.toString(), expression);
} else {
log.info("cache value is null...");
}
}
}
5 .RedisUtil 类
package cn.com.citydo.web.util;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.support.atomic.RedisAtomicLong;
import org.springframework.stereotype.Component;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.serializer.SerializerFeature;
import lombok.extern.slf4j.Slf4j;
/**
*
* Redis缓存工具类
*
* @author yss
*
*/
@Component
@Slf4j
public class RedisUtils {
private static RedisTemplate redisTemplate;
@Autowired
public void setRedisTemplate(RedisTemplate redisTemplate) {
if (null == redisTemplate) {
log.info("Redis初始化配置失败,请检查配置项");
} else {
log.info("Redis初始化配置注入成功!");
}
RedisUtils.redisTemplate = redisTemplate;
}
/**
* 指定缓存失效时间
*
* @param key
* 键
* @param time
* 时间(秒)
* @return
*/
public static boolean expire(String key, long time) {
try {
if (time > 0) {
redisTemplate.expire(key, time, TimeUnit.SECONDS);
}
return true;
} catch (Exception e) {
log.error("expire() is error : {}", e);
return false;
}
}
/**
* 根据key 获取过期时间
*
* @param key
* 键 不能为null
* @return 时间(秒) 返回0代表为永久有效
*/
public static long getExpire(String key) {
return redisTemplate.getExpire(key, TimeUnit.SECONDS);
}
/**
* 判断key是否存在
*
* @param key
* 键
* @return true 存在 false不存在
*/
public static boolean hasKey(String key) {
try {
return redisTemplate.hasKey(key);
} catch (Exception e) {
log.error("hasKey() is error : {}", e);
return false;
}
}
/**
* 普通缓存获取
*
* @param key
* 键
* @return 值
*/
public static Object get(String key) {
return key == null ? null : redisTemplate.opsForValue().get(key);
}
/**
* 普通缓存放入
*
* @param key
* 键
* @param value
* 值
* @return true成功 false失败
*/
public static boolean set(String key, Object value) {
try {
redisTemplate.opsForValue().set(key, value);
return true;
} catch (Exception e) {
log.error("set() is error : {}", e);
return false;
}
}
/**
* 普通缓存放入并设置时间
*
* @param key
* 键
* @param value
* 值
* @param time
* 时间(秒) time要大于0 如果time小于等于0 将设置无限期
* @return true成功 false 失败
*/
public static boolean set(String key, Object value, long time) {
try {
if (time > 0) {
redisTemplate.opsForValue().set(key, value, time, TimeUnit.SECONDS);
} else {
set(key, value);
}
return true;
} catch (Exception e) {
log.error("set() is error : {}", e);
return false;
}
}
/**
* HashGet
*
* @param key
* 键 不能为null
* @param item
* 项 不能为null
* @return 值
*/
public static Object hget(String key, String item) {
return redisTemplate.opsForHash().get(key, item);
}
/**
* 获取hashKey对应的所有键值
*
* @param key
* 键
* @return 对应的多个键值
*/
public static Map hmget(String key) {
return redisTemplate.opsForHash().entries(key);
}
/**
* HashSet
*
* @param key
* 键
* @param map
* 对应多个键值
* @return true 成功 false 失败
*/
public static boolean hmset(String key, Map map) {
try {
redisTemplate.opsForHash().putAll(key, map);
return true;
} catch (Exception e) {
log.error("hmset() is error : {}", e);
return false;
}
}
/**
* HashSet 并设置时间
*
* @param key
* 键
* @param map
* 对应多个键值
* @param time
* 时间(秒)
* @return true成功 false失败
*/
public static boolean hmset(String key, Map map, long time) {
try {
redisTemplate.opsForHash().putAll(key, map);
if (time > 0) {
expire(key, time);
}
return true;
} catch (Exception e) {
log.error("hmset() is error : {}", e);
return false;
}
}
/**
* 向一张hash表中放入数据,如果不存在将创建
*
* @param key
* 键
* @param item
* 项
* @param value
* 值
* @return true 成功 false失败
*/
public static boolean hset(String key, String item, Object value) {
try {
redisTemplate.opsForHash().put(key, item, value);
return true;
} catch (Exception e) {
log.error("hset() is error : {}", e);
return false;
}
}
/**
* 向一张hash表中放入数据,如果不存在将创建
*
* @param key
* 键
* @param item
* 项
* @param value
* 值
* @param time
* 时间(秒) 注意:如果已存在的hash表有时间,这里将会替换原有的时间
* @return true 成功 false失败
*/
public static boolean hset(String key, String item, Object value, long time) {
try {
redisTemplate.opsForHash().put(key, item, value);
if (time > 0) {
expire(key, time);
}
return true;
} catch (Exception e) {
log.error("hset() is error : {}", e);
return false;
}
}
/**
* 删除hash表中的值
*
* @param key
* 键 不能为null
* @param item
* 项 可以使多个 不能为null
*/
public static void hdel(String key, Object... item) {
redisTemplate.opsForHash().delete(key, item);
}
/**
* 判断hash表中是否有该项的值
*
* @param key
* 键 不能为null
* @param item
* 项 不能为null
* @return true 存在 false不存在
*/
public static boolean hHasKey(String key, String item) {
return redisTemplate.opsForHash().hasKey(key, item);
}
/**
* hash递增 如果不存在,就会创建一个 并把新增后的值返回
*
* @param key
* 键
* @param item
* 项
* @param by
* 要增加几(大于0)
* @return
*/
public static double hincr(String key, String item, double by) {
return redisTemplate.opsForHash().increment(key, item, by);
}
/**
* hash递减
*
* @param key
* 键
* @param item
* 项
* @param by
* 要减少记(小于0)
* @return
*/
public static double hdecr(String key, String item, double by) {
return redisTemplate.opsForHash().increment(key, item, -by);
}
/**
* 根据key获取Set中的所有值
*
* @param key
* 键
* @return
*/
public static Set sGet(String key) {
try {
return redisTemplate.opsForSet().members(key);
} catch (Exception e) {
log.error("sGet() is error : {}", e);
return null;
}
}
/**
* 根据value从一个set中查询,是否存在
*
* @param key
* 键
* @param value
* 值
* @return true 存在 false不存在
*/
public static boolean sHasKey(String key, Object value) {
try {
return redisTemplate.opsForSet().isMember(key, value);
} catch (Exception e) {
log.error("sHasKey() is error : {}", e);
return false;
}
}
/**
* 将数据放入set缓存
*
* @param key
* 键
* @param values
* 值 可以是多个
* @return 成功个数
*/
public static long sSet(String key, Object... values) {
try {
return redisTemplate.opsForSet().add(key, values);
} catch (Exception e) {
log.error("sSet() is error : {}", e);
return 0;
}
}
/**
* 将set数据放入缓存
*
* @param key
* 键
* @param time
* 时间(秒)
* @param values
* 值 可以是多个
* @return 成功个数
*/
public static long sSetAndTime(String key, long time, Object... values) {
try {
Long count = redisTemplate.opsForSet().add(key, values);
if (time > 0) {
expire(key, time);
}
return count;
} catch (Exception e) {
log.error("sSetAndTime() is error : {}", e);
return 0;
}
}
/**
* 获取set缓存的长度
*
* @param key
* 键
* @return
*/
public static long sGetSetSize(String key) {
try {
return redisTemplate.opsForSet().size(key);
} catch (Exception e) {
log.error("sGetSetSize() is error : {}", e);
return 0;
}
}
/**
* 移除值为value的
*
* @param key
* 键
* @param values
* 值 可以是多个
* @return 移除的个数
*/
public static long setRemove(String key, Object... values) {
try {
Long count = redisTemplate.opsForSet().remove(key, values);
return count;
} catch (Exception e) {
log.error("setRemove() is error : {}", e);
return 0;
}
}
/**
* 获取list缓存的内容
*
* @param key
* 键
* @param start
* 开始
* @param end
* 结束 0 到 -1代表所有值
* @return
*/
public static List lGet(String key, long start, long end) {
try {
return redisTemplate.opsForList().range(key, start, end);
} catch (Exception e) {
log.error("lGet() is error : {}", e);
return null;
}
}
/**
* 获取list缓存的内容
*
* @param key
* 键
* @return
*/
public static List lGet(String key) {
return lGet(key, 0, -1);
}
/**
* 获取list缓存的长度
*
* @param key
* 键
* @return
*/
public static long lGetListSize(String key) {
try {
return redisTemplate.opsForList().size(key);
} catch (Exception e) {
log.error("lGetListSize() is error : {}", e);
return 0;
}
}
/**
* 通过索引 获取list中的值
*
* @param key
* 键
* @param index
* 索引 index>=0时, 0 表头,1 第二个元素,依次类推;index<0时,-1,表尾,-2倒数第二个元素,依次类推
* @return
*/
public static Object lGetIndex(String key, long index) {
try {
return redisTemplate.opsForList().index(key, index);
} catch (Exception e) {
log.error("lGetIndex() is error : {}", e);
return null;
}
}
/**
* 将list放入缓存
*
* @param key
* 键
* @param value
* 值
* @param time
* 时间(秒)
* @return
*/
public static boolean lSet(String key, Object value) {
try {
redisTemplate.opsForList().rightPush(key, value);
return true;
} catch (Exception e) {
log.error("lSet() is error : {}", e);
return false;
}
}
/**
* 将list放入缓存
*
* @param key
* 键
* @param value
* 值
* @param time
* 时间(秒)
* @return
*/
public static boolean lSet(String key, Object value, long time) {
try {
redisTemplate.opsForList().rightPush(key, value);
if (time > 0) {
expire(key, time);
}
return true;
} catch (Exception e) {
log.error("lSet() is error : {}", e);
return false;
}
}
/**
* 将list放入缓存
*
* @param key
* 键
* @param value
* 值
* @param time
* 时间(秒)
* @return
*/
public static boolean lSet(String key, List value) {
try {
redisTemplate.opsForList().rightPushAll(key, value);
return true;
} catch (Exception e) {
log.error("lSet() is error : {}", e);
return false;
}
}
/**
* 将list放入缓存
*
* @param key
* 键
* @param value
* 值
* @param time
* 时间(秒)
* @return
*/
public static boolean lSet(String key, List value, long time) {
try {
redisTemplate.opsForList().rightPushAll(key, value);
if (time > 0) {
expire(key, time);
}
return true;
} catch (Exception e) {
log.error("lSet() is error : {}", e);
return false;
}
}
/**
* 根据索引修改list中的某条数据
*
* @param key
* 键
* @param index
* 索引
* @param value
* 值
* @return
*/
public static boolean lUpdateIndex(String key, long index, Object value) {
try {
redisTemplate.opsForList().set(key, index, value);
return true;
} catch (Exception e) {
log.error("lUpdateIndex() is error : {}", e);
return false;
}
}
/**
* 移除N个值为value
*
* @param key
* 键
* @param count
* 移除多少个
* @param value
* 值
* @return 移除的个数
*/
public static long lRemove(String key, long count, Object value) {
try {
Long remove = redisTemplate.opsForList().remove(key, count, value);
return remove;
} catch (Exception e) {
log.error("lRemove() is error : {}", e);
return 0;
}
}
/**
*
* 获取对象
*
* @param key
* @param clazz
* @return
*/
public static T getObjectBean(String key, Class clazz) {
String value = (String) redisTemplate.opsForValue().get(key);
return parseJson(value, clazz);
}
/**
* 存放对象
*
* @param key
* @param obj
*/
public static void setObjectBean(String key, T obj) {
if (obj == null) {
return;
}
String value = toJson(obj);
redisTemplate.opsForValue().set(key, value);
}
/**
* 存放对象并返回该对象
*
* @param key
* @param obj
*/
public static T getAndSet(String key, T obj, Class clazz) {
if (obj == null) {
return getObjectBean(key, clazz);
}
String value = (String) redisTemplate.opsForValue().getAndSet(key, toJson(obj));
return parseJson(value, clazz);
}
/**
* 原子自增
*
* @param key
* @return
*/
public static long generate(String key) {
RedisAtomicLong counter = new RedisAtomicLong(key, redisTemplate.getConnectionFactory());
return counter.incrementAndGet();
}
/**
* A原子自增
*
* @param key
* @param expireTime
* @return
*/
public static long generate(String key, Date expireTime) {
RedisAtomicLong counter = new RedisAtomicLong(key, redisTemplate.getConnectionFactory());
counter.expireAt(expireTime);
return counter.incrementAndGet();
}
/**
* 原子自增
*
* @param key
* @param increment
* @return
*/
public static long generate(String key, int increment) {
RedisAtomicLong counter = new RedisAtomicLong(key, redisTemplate.getConnectionFactory());
return counter.addAndGet(increment);
}
/**
* 原子自增
*
* @param key
* @param increment
* @param expireTime
* @return
*/
public static long generate(String key, int increment, Date expireTime) {
RedisAtomicLong counter = new RedisAtomicLong(key, redisTemplate.getConnectionFactory());
counter.expireAt(expireTime);
return counter.addAndGet(increment);
}
/**
* 序列化对象为JSONString
*
* @param obj
* @return
*/
public static String toJson(Object obj) {
return JSON.toJSONString(obj, SerializerFeature.SortField);
}
/**
* 序列化JSON为ObjectBean
*
* @param obj
* @return
*/
public static T parseJson(String json, Class clazz) {
return JSON.parseObject(json, clazz);
}
/**
* 序列化List对象
*
* @param key
* @param clazz
* @return
*/
public static List getList(String key, Class clazz) {
try {
Object cache = get(key);
if (null != cache && StringUtils.isNotBlank(cache.toString())) {
List cacheList = JSONArray.parseArray(JSONArray.parseArray(cache.toString()).toJSONString(), clazz);
return cacheList;
}
} catch (Exception e) {
log.error("redis查询异常,e:", e);
}
return null;
}
/**
* 将List作为JSONString存入缓存
*
* @param key
* @param list
*/
public static void setList(String key, List list) {
if (StringUtils.isBlank(key) || CollectionUtils.isEmpty(list)) {
return;
}
set(key, toJson(list));
}
}