版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/liu689118/article/details/82021908
在项目开发中redisCacheUtils
package com.sf.stms.server.redis;
import java.time.Duration;
import java.time.Instant;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.sf.stms.common.domain.RedisSelectRules;
import com.sf.stms.common.utils.ListUtil;
import com.sf.stms.common.utils.PropertiesUtils;
import com.sf.stms.server.cache.NormalDataCacheHelper;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPoolConfig;
import redis.clients.jedis.JedisPubSub;
import redis.clients.jedis.JedisSentinelPool;
import redis.clients.jedis.ScanParams;
import redis.clients.jedis.ScanResult;
/**
* 描述:RedisUtil
* @author 80002888
* @date 2018年6月21日
*/
public class RedisCacheUtils {
private static final Logger log = LoggerFactory.getLogger(RedisCacheUtils.class);
private static Map<String, JedisSentinelPool> poolMap;
/**
* 默认为配置中最后一个redis服务器
*/
private static final JedisSentinelPool DEFAULT_POOL;
private static String[] mastersArr;
/**
* 初始化
*/
static {
JedisPoolConfig config = new JedisPoolConfig();
// 连接池中连接最大数量
config.setMaxTotal(200);
// 最大空闲连接数量
config.setMaxIdle(100);
// 获取连接最长等待时间ms
config.setMaxWaitMillis(100);
config.setTestOnBorrow(true);
config.setTestOnReturn(true);
config.setTestWhileIdle(true);
String jpassword = PropertiesUtils.getValue("/properties/redis.properties", "redis_password");
//超时时间(单位毫秒,2.8以下即是连接超时时间,又是读写超时时间)
int timeout = Integer.parseInt(PropertiesUtils.getValue("/properties/redis.properties", "redis_time"));
String masters = PropertiesUtils.getValue("/properties/redis.properties", "redis_masters");
mastersArr = masters.split(",");
int size = mastersArr.length;
Set<String> sentinels = new HashSet<String>();
String sentinelsd = PropertiesUtils.getValue("/properties/redis.properties", "redis_servers");
String[] sentinelsArr = sentinelsd.split(",");
sentinels.addAll(Arrays.asList(sentinelsArr));
poolMap = new HashMap<>();
for (int i = 0; i < size; i++) {
String masterName = mastersArr[i];
poolMap.put(masterName, new JedisSentinelPool(masterName, sentinels, config, timeout, jpassword));
}
DEFAULT_POOL = new JedisSentinelPool(mastersArr[size-1], sentinels, config, timeout, jpassword);
}
/**
* 从redis获取数据
* @ReturnType String
* @Date 2018年1月23日 上午11:37:00
* @Param @param key
* @Param @return
*/
public static String get(String key) {
String value = null;
Jedis jedis = null;
JedisSentinelPool pool = getPool(key);
try {
if (pool == null) {
pool = DEFAULT_POOL;
}
jedis = pool.getResource();
value = jedis.get(key);
} catch (Exception e) {
pool.returnBrokenResource(jedis);
log.error("redis get ===>", e);
} finally {
returnResource(pool, jedis);
}
return value;
}
/**
* 向redis设置数据,默认一个月
* @ReturnType void
* @Date 2018年1月23日 上午11:36:50
* @Param @param key
* @Param @param value
*/
public static void set(String key, String value) {
setOneMonth(key, value);
}
/**
* 向redis设置数据
* @ReturnType void
* @Date 2018年1月23日 上午11:45:09
* @Param @param key
* @Param @param value
* @Param @param seconds 存活的秒数
*/
public static void set(String key, String value, int seconds) {
Jedis jedis = null;
JedisSentinelPool pool = getPool(key);
try {
if (pool == null) {
pool = DEFAULT_POOL;
}
jedis = pool.getResource();
value = jedis.setex(key, seconds, value);
} catch (Exception e) {
pool.returnBrokenResource(jedis);
log.error("redis set ===>", e);
} finally {
returnResource(pool, jedis);
}
return;
}
/**
* 永久存储
* @ReturnType void
* @Date 2018年1月23日 上午11:45:09
* @Param @param key
* @Param @param value
*/
public static void setForever(String key, String value) {
set(key, value, (60*60*24*30*12*100));
}
/**
* 存储一个月
* @ReturnType void
* @Date 2018年1月23日 上午11:45:09
* @Param @param key
* @Param @param value
*/
public static void setOneMonth(String key, String value) {
set(key, value, (60*60*24*30));
}
/**
* 设置过期时间
* @ReturnType void
* @Date 2018年1月23日 上午11:45:58
* @Param @param key
* @Param @param seconds
*/
public static void expire(String key, int seconds) {
Jedis jedis = null;
JedisSentinelPool pool = getPool(key);
try {
if (pool == null) {
pool = DEFAULT_POOL;
}
jedis = pool.getResource();
jedis.expire(key, seconds);
} catch (Exception e) {
pool.returnBrokenResource(jedis);
log.error("redis set ===>", e);
} finally {
returnResource(pool, jedis);
}
return;
}
/**
* 是否存在key
* @ReturnType boolean
* @Date 2018年1月23日 上午11:46:41
* @Param @param key
* @Param @return
*/
public static boolean exists(String key){
Jedis jedis = null;
JedisSentinelPool pool = getPool(key);
try {
if (pool == null) {
pool = DEFAULT_POOL;
}
jedis = pool.getResource();
return jedis.exists(key);
} catch (Exception e) {
pool.returnBrokenResource(jedis);
log.error("redis set ===>", e);
} finally {
returnResource(pool, jedis);
}
return false;
}
/**
* 查看数据的生存时间
* @ReturnType Long
* @Date 2018年1月23日 上午11:37:00
* @Param @param key
* @Param @return 单位是秒,-2为数据不存在,-1为永不过期
*/
public static Long ttl(String key) {
Long seconds = null;
Jedis jedis = null;
JedisSentinelPool pool = getPool(key);
try {
if (pool == null) {
pool = DEFAULT_POOL;
}
jedis = pool.getResource();
seconds = jedis.ttl(key);
} catch (Exception e) {
pool.returnBrokenResource(jedis);
log.error("redis ttl ===>", e);
} finally {
returnResource(pool, jedis);
}
return seconds;
}
/**
* 从redis获取keys
* @ReturnType String
* @Date 2018年1月23日 上午11:37:00
* @Param @param key
* @Param @return
*/
public static Collection<String> getKeys(String pattern) {
Collection<String> keys = new HashSet<>();
Collection<JedisSentinelPool> pools = poolMap.values();
if (CollectionUtils.isEmpty(pools)) {
return null;
}
for (JedisSentinelPool pool : pools) {
Collection<String> keysFromOnePool = getKeysFromOnePool(pattern, pool);
if (CollectionUtils.isNotEmpty(keysFromOnePool)) {
keys.addAll(keysFromOnePool);
}
}
if (CollectionUtils.isEmpty(keys)) {
return null;
}
return keys;
}
/**
* 按key移除
* @ReturnType void
* @Date 2018年1月23日 上午11:36:25
* @Param @param key
*/
public static void remove(String key) {
Jedis jedis = null;
JedisSentinelPool pool = getPool(key);
try {
jedis = pool.getResource();
jedis.del(key);
} catch (Exception e) {
pool.returnBrokenResource(jedis);
log.error("redis del ===> ", e);
} finally {
returnResource(pool, jedis);
}
return;
}
/**********************************************************************/
/**
* 向redis批量设置数据,默认30天
* @ReturnType void
* @Date 2018年1月23日 上午11:45:09
* @Param @param map
*/
public static void setBatch(Map<String, String> datas) {
setBatch(datas, (60*60*24*30));
}
/**
* 向redis批量设置数据
* @ReturnType void
* @Date 2018年1月23日 上午11:45:09
* @Param @param map
* @Param @param seconds
*/
public static void setBatch(Map<String, String> datas, int seconds) {
if (datas == null || datas.size() == 0 || CollectionUtils.isEmpty(datas.keySet())) {
return;
}
Map<JedisSentinelPool, List<String>> map = datas.keySet().stream().filter((x)->StringUtils.isNotBlank(x)).collect(Collectors.groupingBy(RedisCacheUtils::getPool));
for (JedisSentinelPool pool : map.keySet()) {
Jedis jedis = null;
try {
jedis = pool.getResource();
List<String> keys = map.get(pool);
if (CollectionUtils.isEmpty(keys)) {
continue;
}
for (String key : keys) {
if (StringUtils.isBlank(key)) {
continue;
}
String value = datas.get(key);
if (StringUtils.isBlank(value)) {
continue;
}
jedis.setex(key, seconds, value);
}
} catch (Exception e) {
pool.returnBrokenResource(jedis);
log.error("redis setBatch ===> ", e);
} finally {
returnResource(pool, jedis);
}
}
}
/**
* 按keys批量移除
* @ReturnType long
* @Date 2018年1月30日 下午7:13:12
* @Param @return 删除的数量
*/
public static long removeBatch(List<String> keys){
if (CollectionUtils.isEmpty(keys)) {
return 0;
}
int total = 0;
Map<JedisSentinelPool, List<String>> map = keys.stream().filter(StringUtils::isNotBlank).collect(Collectors.groupingBy(RedisCacheUtils::getPool));
for (JedisSentinelPool pool : map.keySet()) {
Jedis jedis = null;
try {
jedis = pool.getResource();
List<String> list = map.get(pool);
if (CollectionUtils.isEmpty(list)) {
continue;
}
total += jedis.del(ListUtil.listToArray(list));
} catch (Exception e) {
pool.returnBrokenResource(jedis);
log.error("redis del batch ===> ", e);
} finally {
returnResource(pool, jedis);
}
}
return total;
}
/**
* 按keys批量获取
* @ReturnType String
* @Date 2018年1月30日 下午8:02:59
* @Param @param keys
* @Param @return
*/
public static List<String> getBatch(List<String> keys){
if (CollectionUtils.isEmpty(keys)) {
return null;
}
List<String> totalValues = new ArrayList<>();
Map<JedisSentinelPool, List<String>> map = keys.stream().filter(StringUtils::isNotBlank).collect(Collectors.groupingBy(RedisCacheUtils::getPool));
for (JedisSentinelPool pool : map.keySet()) {
Jedis jedis = null;
try {
jedis = pool.getResource();
List<String> list = map.get(pool);
if (CollectionUtils.isEmpty(list)) {
continue;
}
List<String> values = jedis.mget(ListUtil.listToArray(list));
if (CollectionUtils.isEmpty(values)) {
continue;
}
totalValues.addAll(values);
} catch (Exception e) {
pool.returnBrokenResource(jedis);
log.error("redis getBatch ===> ", e);
} finally {
returnResource(pool, jedis);
}
}
if (CollectionUtils.isEmpty(totalValues)) {
return null;
}
return totalValues;
}
/**
* 订阅频道
* @ReturnType void
* @Date 2018年2月3日 下午3:23:32
* @Param @param jedisPubSub
* @Param @param channel
*/
public static void subscribe(JedisPubSub jedisPubSub, String...channels){
if(DEFAULT_POOL == null){
return;
}
if (jedisPubSub == null) {
return;
}
if (channels == null || channels.length == 0) {
return;
}
Jedis jedis = null;
try {
jedis = DEFAULT_POOL.getResource();
jedis.subscribe(jedisPubSub, channels);
} catch (Exception e) {
DEFAULT_POOL.returnBrokenResource(jedis);
log.error("redis subscribe ===> ", e);
} finally {
returnResource(DEFAULT_POOL, jedis);
}
}
/**
* 向频道发布内容
* @ReturnType void
* @Date 2018年7月23日 下午2:05:27
* @Param @param channel
* @Param @param message
*/
public static void publish(String channel, String message){
if(DEFAULT_POOL == null){
return;
}
if (StringUtils.isBlank(channel) || StringUtils.isBlank(message)) {
return;
}
Jedis jedis = null;
try {
jedis = DEFAULT_POOL.getResource();
jedis.publish(channel, message);
} catch (Exception e) {
DEFAULT_POOL.returnBrokenResource(jedis);
log.error("redis publish ===> ", e);
} finally {
returnResource(DEFAULT_POOL, jedis);
}
}
/**
* 向redis的set结构添加数据(添加在头部)
* @ReturnType void
* @Date 2018年8月22日 下午3:42:37
* @Param @param setName set的名称
* @Param @param values 要添加的数据
*/
public static void lpush(String setName, String...values){
Jedis jedis = null;
JedisSentinelPool pool = getPool(setName);
try {
jedis = pool.getResource();
jedis.lpush(setName, values);
} catch (Exception e) {
pool.returnBrokenResource(jedis);
log.error("redis lpush ===> ", e);
} finally {
returnResource(pool, jedis);
}
return;
}
/**
* 向redis的set结构添加数据(添加在尾部)
* @ReturnType void
* @Date 2018年8月22日 下午3:42:37
* @Param @param setName set的名称
* @Param @param values 要添加的数据
*/
public static void rpush(String setName, String...values){
Jedis jedis = null;
JedisSentinelPool pool = getPool(setName);
try {
jedis = pool.getResource();
jedis.rpush(setName, values);
} catch (Exception e) {
pool.returnBrokenResource(jedis);
log.error("redis rpush ===> ", e);
} finally {
returnResource(pool, jedis);
}
return;
}
/**
* 从redis的set结构弹出数据(从头部获取并删除)
* @ReturnType String
* @Date 2018年8月22日 下午3:50:59
* @Param @param setName set的名称
* @Param @return 获取到的value
*/
public static String lpop(String setName){
Jedis jedis = null;
JedisSentinelPool pool = getPool(setName);
try {
jedis = pool.getResource();
String value = jedis.lpop(setName);
return value;
} catch (Exception e) {
pool.returnBrokenResource(jedis);
log.error("redis lpop ===> ", e);
} finally {
returnResource(pool, jedis);
}
return null;
}
/**
* 从redis的set结构弹出数据(从尾部获取并删除)
* @ReturnType void
* @Date 2018年8月22日 下午3:42:37
* @Param @param setName set的名称
* @Param @return 获取到的value
*/
public static void rpop(String setName){
Jedis jedis = null;
JedisSentinelPool pool = getPool(setName);
try {
jedis = pool.getResource();
jedis.rpop(setName);
} catch (Exception e) {
pool.returnBrokenResource(jedis);
log.error("redis rpop ===> ", e);
} finally {
returnResource(pool, jedis);
}
return;
}
/**
* 从redis的set结构弹出数据(阻塞从头部获取并删除)
* @ReturnType String
* @Date 2018年8月22日 下午3:50:59
* @Param @param timeout 超时时间(s)
* @Param @param setName set的名称
* @Param @return 如果超时且取不到,则为null。
* 如果取到了,list(0)为key,list(1)为value(一次只弹出一个元素)
*/
public static List<String> blpop(int timeout, String setName){
Jedis jedis = null;
JedisSentinelPool pool = getPool(setName);
try {
jedis = pool.getResource();
List<String> resList = jedis.blpop(timeout, setName);
return resList;
} catch (Exception e) {
pool.returnBrokenResource(jedis);
log.error("redis blpop ===> ", e);
} finally {
returnResource(pool, jedis);
}
return null;
}
/**
* 从redis的set结构弹出数据(阻塞从尾部获取并删除)
* @ReturnType String
* @Date 2018年8月22日 下午3:50:59
* @Param @param timeout 超时时间(s)
* @Param @param setName set的名称
* @Param @return 如果超时且取不到,则为null。
* 如果取到了,list(0)为key,list(1)为value(一次只弹出一个元素)
*/
public static List<String> brpop(int timeout, String setName){
Jedis jedis = null;
JedisSentinelPool pool = getPool(setName);
try {
jedis = pool.getResource();
List<String> resList = jedis.brpop(timeout, setName);
return resList;
} catch (Exception e) {
pool.returnBrokenResource(jedis);
log.error("redis brpop ===> ", e);
} finally {
returnResource(pool, jedis);
}
return null;
}
/******************************************************************************/
/**
* 根据key获取JedisSentinelPool
*/
protected static JedisSentinelPool getPool(String key){
if (StringUtils.isBlank(key)) {
return DEFAULT_POOL;
}
String masterName = getMasterName(key);
if (StringUtils.isBlank(masterName)) {
// 按HashCode
int index = Math.abs(key.hashCode() % mastersArr.length);
masterName = mastersArr[index];
}
JedisSentinelPool pool = getPoolByMasterName(masterName);
if (pool == null) {
return DEFAULT_POOL;
}
return pool;
}
/**
* 根据主机名称获取 JedisSentinelPool
*/
protected static JedisSentinelPool getPoolByMasterName(String masterName){
if (StringUtils.isBlank(masterName)) {
return null;
}
JedisSentinelPool pool = poolMap.get(masterName);
return pool;
}
/**
* 从数据库根据redis中的key查询所属pool的masterName
*/
private static String getMasterName(String key) {
if(StringUtils.isBlank(key)){
return null;
}
List<RedisSelectRules> redisSelectRulesList = NormalDataCacheHelper.getRedisSelectRulesCache();
if (CollectionUtils.isEmpty(redisSelectRulesList)) {
return null;
}
redisSelectRulesList = redisSelectRulesList.stream().sorted((r1,r2)->r1.getPriority().compareTo(r2.getPriority())).collect(Collectors.toList());
for (RedisSelectRules item : redisSelectRulesList) {
if (key.contains(item.getSelectParam())) {
return item.getMasterName();
}
}
return null;
}
/**
* 把jedis连接交给连接池
*/
protected static void returnResource(JedisSentinelPool pool, Jedis jedis) {
if (pool != null && jedis != null) {
pool.returnResource(jedis);
}
}
/**
* 根据通配符从指定redis服务器查询keys,使用scan命令代替jedis.keys(pattern)
*/
protected static Collection<String> getKeysFromOnePool(String pattern, JedisSentinelPool pool){
Jedis jedis = null;
Set<String> keys = null;
String startCursor = "0";
try {
jedis = pool.getResource();
keys = new HashSet<>();
String cursor = startCursor;
Instant start = Instant.now();
do {
ScanResult<String> scanResult = jedis.scan(cursor, new ScanParams().count(1000).match(pattern));
List<String> results = scanResult.getResult();
cursor = scanResult.getStringCursor();
if (CollectionUtils.isEmpty(results)) {
continue;
}
keys.addAll(new HashSet<>(results));
} while (!startCursor.equals(cursor) && (Duration.between(start, Instant.now()).toMillis()<=1000*60));
} catch (Exception e) {
pool.returnBrokenResource(jedis);
log.error("redis get ===>", e);
} finally {
returnResource(pool, jedis);
}
if (CollectionUtils.isEmpty(keys)) {
return null;
}
return keys;
}
public static JedisSentinelPool getDefaultPool(){
return DEFAULT_POOL;
}
/**
* 销毁连接池
*/
public static void destroyPool(){
poolMap.values().forEach((x)->x.destroy());
DEFAULT_POOL.destroy();
}
}
2.使用redis实现分布式锁 lock(String key,int timeout) 来保证数据数据原子性,在插入和修改数据保证数据的并发