在项目开发中redisCacheUtils

1 篇文章 0 订阅

在项目开发中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)  来保证数据数据原子性,在插入和修改数据保证数据的并发

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值