package com.ljsd.redis; import com.ljsd.util.BaseGlobal; import com.ljsd.util.TimeUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import redis.clients.jedis.Jedis; import redis.clients.jedis.JedisPool; import redis.clients.jedis.JedisPoolConfig; import java.util.*; public class RedisUtil { private static final Logger LOGGER = LoggerFactory.getLogger(RedisUtil.class); private static int MAX_TRY_TIMES = 3; //最大尝试次数,保障获取/存储成功 private static int FAILED_SLEEP = 2; //每次失败最大停顿时间 private JedisPool jedisPool;//非切片连接池 protected void init() { // 池基本配置 JedisPoolConfig config = new JedisPoolConfig(); Properties properties = BaseGlobal.getInstance().properties; config.setMaxTotal(Integer.parseInt(properties.getProperty("redis_maxTotal"))); config.setMinIdle(Integer.parseInt(properties.getProperty("redis_minIdle"))); config.setMaxWaitMillis(Integer.parseInt(properties.getProperty("redis_maxWaitMillis"))); config.setMaxIdle(Integer.parseInt(properties.getProperty("redis_maxIdle"))); config.setTestOnBorrow(Boolean.parseBoolean(properties.getProperty("redis_testOnBorrow"))); if (properties.getProperty("redis_password") ==null || properties.getProperty("redis_password").isEmpty()){ jedisPool = new JedisPool(config, properties.getProperty("redis_host"), Integer.parseInt(properties.getProperty("redis_port")),0); }else{ jedisPool = new JedisPool(config, properties.getProperty("redis_host"), Integer.parseInt(properties.getProperty("redis_port")),0,properties.getProperty("redis_password")); } } /***************************************普通键值对操作***************************************/ //设置键值 protected void set(final String key, String value) throws Exception { for (int i = 0; i < MAX_TRY_TIMES; i++) { Jedis jedis = jedisPool.getResource(); try { jedis.set(key, value); return; } catch (Exception e) { LOGGER.error("set->i={}: key={}, value={}", i, key, value, e); TimeUtil.sleep(FAILED_SLEEP); } finally { jedis.close(); } } throw new Exception("RedisUtil::set exception"); } //设置键值,带过期时间 protected void setex(final String key, final int seconds, final String value) throws Exception { for (int i = 0; i < MAX_TRY_TIMES; i++) { Jedis jedis = jedisPool.getResource(); try { jedis.setex(key, seconds, value); return; } catch (Exception e) { LOGGER.error("setex->i={},key={},value={},seconds={}", i, key, value, seconds, e); TimeUtil.sleep(FAILED_SLEEP); } finally { jedis.close(); } } throw new Exception("RedisUtil::setex exception"); } //取得键的值 protected String get(final String key) throws Exception { for (int i = 0; i < MAX_TRY_TIMES; i++) { Jedis jedis = jedisPool.getResource(); try { return jedis.get(key); } catch (Exception e) { LOGGER.error("get->i={},key={}", i, key, e); TimeUtil.sleep(FAILED_SLEEP); } finally { jedis.close(); } } throw new Exception("RedisUtil::get exception"); } //删除键值 protected void del(String key) throws Exception { for (int i = 0; i < MAX_TRY_TIMES; i++) { Jedis jedis = jedisPool.getResource(); try { jedis.del(key); return; } catch (Exception e) { LOGGER.error("del->i={},key={}", i, key, e); TimeUtil.sleep(FAILED_SLEEP); } finally { jedis.close(); } } throw new Exception("RedisUtil::del exception"); } //删除键值 protected boolean exists(String key) throws Exception { for (int i = 0; i < MAX_TRY_TIMES; i++) { Jedis jedis = jedisPool.getResource(); try { return jedis.exists(key); } catch (Exception e) { LOGGER.error("exists->i={},key={}", i, key, e); TimeUtil.sleep(FAILED_SLEEP); } finally { jedis.close(); } } throw new Exception("RedisUtil::exists exception"); } //设置过期时间 protected Long expire(final String key, final int seconds) throws Exception { if (seconds <= 0) { return 0L; } for (int i = 0; i < MAX_TRY_TIMES; i++) { Jedis jedis = jedisPool.getResource(); try { return jedis.expire(key, seconds); } catch (Exception e) { LOGGER.error("expire->i={},key={},seconds={}", i, key, seconds, e); TimeUtil.sleep(FAILED_SLEEP); } finally { jedis.close(); } } throw new Exception("RedisUtil::del exception"); } /***************************************以下是map操作***************************************/ //添加redis map protected void hmset(final String key, final Map hash, int seconds) throws Exception { int i; for (i = 0; i < MAX_TRY_TIMES; i++) { Jedis jedis = jedisPool.getResource(); try { jedis.hmset(key, hash); break; } catch (Exception e) { LOGGER.error("hmset->i={},key={}", i, key, e); TimeUtil.sleep(FAILED_SLEEP); } finally { jedis.close(); } } expire(key, seconds); if (i >= MAX_TRY_TIMES) { throw new Exception("RedisUtil::hmset exception"); } } //取得主key下的所有子key protected Set hkeys(final String key) throws Exception { for (int i = 0; i < MAX_TRY_TIMES; i++) { Jedis jedis = jedisPool.getResource(); try { Set keySet = jedis.hkeys(key); return keySet; } catch (Exception e) { LOGGER.error("hkeys->i={},key={}", i, key, e); TimeUtil.sleep(FAILED_SLEEP); } finally { jedis.close(); } } throw new Exception("RedisUtil::hkeys exception"); } //设置redis map一个键值 下的子key下的值 protected void hset(final String key, final String field, final String value, int seconds) throws Exception { for (int i = 0; i < MAX_TRY_TIMES; i++) { Jedis jedis = jedisPool.getResource(); try { jedis.hset(key, field, value); return; } catch (Exception e) { LOGGER.error("hset->i={},key={},field={},value={}", i, key, field, value, e); TimeUtil.sleep(FAILED_SLEEP); } finally { jedis.close(); } } expire(key, seconds); throw new Exception("RedisUtil::hset exception"); } //取redis map全部数据的直接方法 protected Map hgetAll(final String key) throws Exception { for (int i = 0; i < MAX_TRY_TIMES; i++) { Jedis jedis = jedisPool.getResource(); try { return jedis.hgetAll(key); } catch (Exception e) { LOGGER.error("hgetAll->i={},key={}", i, key, e); TimeUtil.sleep(FAILED_SLEEP); } finally { jedis.close(); } } throw new Exception("RedisUtil::hgetAll exception"); } //获取redis map下一个key的值的直接方法 protected List hmget(final String key, final String... fields) throws Exception { for (int i = 0; i < MAX_TRY_TIMES; i++) { Jedis jedis = jedisPool.getResource(); try { return jedis.hmget(key, fields); } catch (Exception e) { LOGGER.error("hmget->i={},key={}", i, key, e); TimeUtil.sleep(FAILED_SLEEP); } finally { jedis.close(); } } throw new Exception("RedisUtil::hmget exception"); } //删除子key protected void hdel(final String key, final String... fields) throws Exception { for (int i = 0; i < MAX_TRY_TIMES; i++) { Jedis jedis = jedisPool.getResource(); try { jedis.hdel(key, fields); return; } catch (Exception e) { LOGGER.error("hdel->i={},key={},fields={}", i, key, fields, e); TimeUtil.sleep(FAILED_SLEEP); } finally { jedis.close(); } } throw new Exception("RedisUtil::hdel exception"); } /***************************************以下是list操作***************************************/ //添加list数据 protected long lpush(final String key, final int seconds, final String... strings) throws Exception { for (int i = 0; i < MAX_TRY_TIMES; i++) { Jedis jedis = jedisPool.getResource(); try { return jedis.lpush(key, strings); } catch (Exception e) { LOGGER.error("lpush->i={},key={},value={}", i, key, e); TimeUtil.sleep(FAILED_SLEEP); } finally { jedis.close(); } } expire(key, seconds); throw new Exception("RedisUtil::lpush exception"); } protected void ltrim(final String key, final int start, final int end) throws Exception { for (int i = 0; i < MAX_TRY_TIMES; i++) { Jedis jedis = jedisPool.getResource(); try { jedis.ltrim(key, start, end); return; } catch (Exception e) { LOGGER.error("lpush->i={},key={},value={}", i, key, e); TimeUtil.sleep(FAILED_SLEEP); } finally { jedis.close(); } } throw new Exception("RedisUtil::ltrim exception"); } //删除元素 protected void lrem(final String key, final long count, final String value) throws Exception { for (int i = 0; i < MAX_TRY_TIMES; i++) { Jedis jedis = jedisPool.getResource(); try { jedis.lrem(key, count, value); return; } catch (Exception e) { LOGGER.error("lrem->i={},key={},count={},value={}", i, key, count, value, e); TimeUtil.sleep(FAILED_SLEEP); } finally { jedis.close(); } } throw new Exception("RedisUtil::lrem exception"); } //移除最好的元素 protected String rpop(final String key) throws Exception { for (int i = 0; i < MAX_TRY_TIMES; i++) { Jedis jedis = jedisPool.getResource(); try { return jedis.rpop(key); } catch (Exception e) { LOGGER.error("rpop->i={},key={}", i, key, e); TimeUtil.sleep(FAILED_SLEEP); } finally { jedis.close(); } } throw new Exception("RedisUtil::rpop exception"); } //取得指定范围的元素 protected List lrange(final String key, final long start, final long end) throws Exception { for (int i = 0; i < MAX_TRY_TIMES; i++) { Jedis jedis = jedisPool.getResource(); try { return jedis.lrange(key, start, end); } catch (Exception e) { LOGGER.error("lrange->i={},key={},start={},end={}", i, key, start, end, e); TimeUtil.sleep(FAILED_SLEEP); } finally { jedis.close(); } } throw new Exception("RedisUtil::lrange exception"); } //取得list的长度 protected Long llen(final String key) throws Exception { for (int i = 0; i < MAX_TRY_TIMES; i++) { Jedis jedis = jedisPool.getResource(); try { return jedis.llen(key); } catch (Exception e) { LOGGER.error("llen->i={},key={}", i, key, e); TimeUtil.sleep(FAILED_SLEEP); } finally { jedis.close(); } } throw new Exception("RedisUtil::llen exception"); } //自增 protected Long incr(final String key) throws Exception { for (int i = 0; i < MAX_TRY_TIMES; i++) { Jedis jedis = jedisPool.getResource(); try { return jedis.incr(key); } catch (Exception e) { LOGGER.error("incr->i={},key={}", i, key, e); TimeUtil.sleep(FAILED_SLEEP); } finally { jedis.close(); } } throw new Exception("RedisUtil::incr exception"); } private static final String LOCK_SUCCESS = "OK"; private static final String SET_IF_NOT_EXIST = "NX"; private static final String SET_WITH_EXPIRE_TIME = "PX"; /** * 尝试获取分布式锁 * * @param lockKey 锁 * @param requestId 请求标识 * @param expireTime 超期时间,理论上应该比较短,一次请求在500毫秒内即可完成,因此过期时间不应大于1秒 * @return 是否获取成功 */ protected boolean tryGetDistributedLock(String lockKey, String requestId, int expireTime) throws Exception { for (int i = 0; i < MAX_TRY_TIMES; i++) { Jedis jedis = jedisPool.getResource(); try { String result = jedis.set(lockKey, requestId, SET_IF_NOT_EXIST, SET_WITH_EXPIRE_TIME, expireTime); if (LOCK_SUCCESS.equals(result)) { return true; } LOGGER.error("tryGetDistributedLock->i={},key={};failed", i, lockKey); TimeUtil.sleep(200); //理论上锁冲突的几率很小,如果连续三次加锁失败,直接抛出异常 } catch (Exception e) { LOGGER.error("tryGetDistributedLock->i={},key={}", i, lockKey, e); TimeUtil.sleep(FAILED_SLEEP); } finally { jedis.close(); } } throw new Exception("RedisUtil::tryGetDistributedLock exception"); } private static final Long RELEASE_SUCCESS = 1L; /** * 释放分布式锁 * * @param lockKey 锁 * @param requestId 请求标识 * @return 是否释放成功 */ protected boolean releaseDistributedLock(String lockKey, String requestId) throws Exception { for (int i = 0; i < MAX_TRY_TIMES; i++) { Jedis jedis = jedisPool.getResource(); try { String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end"; Object result = jedis.eval(script, Collections.singletonList(lockKey), Collections.singletonList(requestId)); if (RELEASE_SUCCESS.equals(result)) { return true; } return false; //解锁失败,等待过期自动解锁即可 } catch (Exception e) { LOGGER.error("releaseDistributedLock->i={},key={}", i, lockKey, e); TimeUtil.sleep(FAILED_SLEEP); } finally { jedis.close(); } } throw new Exception("RedisUtil::releaseDistributedLock exception"); } }