使用方式
try { if(PublicLock.getLock(lockKey)){ //這里寫代碼邏輯,執行完后需要釋放鎖 PublicLock.freeLock(lockKey); } } catch (Exception e) { //產生異常也需要釋放鎖 PublicLock.freeLock(lockKey); LOGGER.error(e); }
redis的分布式鎖工具類的基礎類
package com.qlchat.redis.cache;
import java.util.*;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.exceptions.JedisException;
import com.qlchat.common.util.JedisUtil;
import com.qlchat.common.util.QlchatUtil;
/**
* 默認操作redis庫是DEFAULT_REDIS_DB = 1
* @author zhangk
*
*/
public class BaseCache extends JedisUtil {
private static Logger log = LoggerFactory.getLogger(BaseCache.class);
private static Long REDIS_INCR_MAX = 4294967294L;
private static int DEFAULT_REDIS_DB = 0;//默認redis庫
/**
*
* 設置value
*
* @since 1.0.0
*/
public static void setValue(String key, String value, Integer expire) {
Jedis jedis = getJedis();
try {
// 如果存在則插入覆蓋,如果不存在則初始化
if(expire != null){
Long ttl = jedis.ttl(key);
jedis.set(key, value);
if(ttl != null && ttl > 0){
jedis.expire(key, ttl.intValue());
}else{
jedis.expire(key, expire);
}
}else{
jedis.set(key, value);
}
} catch (JedisException e) {
log.error(e.getMessage(),e);
} catch (Exception e) {
log.error(e.getMessage(),e);
} finally {
if (jedis != null) {
jedis.close();
}
}
}
public static void setHashFieldValue(String key, String field, String value) {
setHashFieldValue(key, field, value, null);
}
/**
*
* 更新或新增緩存信息
*
* @since 1.0.0
*/
public static void setHashFieldValue(String key, String field, String value, Integer expire) {
Jedis jedis = getJedis();
try {
if(expire != null){
Long ttl = jedis.ttl(key);
jedis.hset(key, field, value);
if(ttl != null && ttl > 0){
jedis.expire(key, ttl.intValue());
}else{
jedis.expire(key, expire);
}
}else{
jedis.hset(key, field, value);
}
} catch (JedisException e) {
log.error(e.getMessage(),e);
} catch (Exception e) {
log.error(e.getMessage(),e);
} finally {
if (jedis != null) {
jedis.close();
}
}
}
public static void setHashMapValue(String key, Map<String, String> map, Integer expire) {
setHashMapValue(key, map, DEFAULT_REDIS_DB, expire);
}
/**
*
* 更新或新增緩存信息
*
* @exception
* @since 1.0.0
*/
public static void setHashMapValue(String key, Map<String, String> map, int db, Integer expire) {
Jedis jedis = getJedis();
try {
if(expire != null){
Long ttl = jedis.ttl(key);
jedis.hmset(key, map);
if(ttl != null && ttl > 0){
jedis.expire(key, ttl.intValue());
}else{
jedis.expire(key, expire);
}
}else{
jedis.hmset(key, map);
}
} catch (JedisException e) {
log.error(e.getMessage(),e);
} catch (Exception e) {
log.error(e.getMessage(),e);
} finally {
if (jedis != null) {
jedis.close();
}
}
}
public static String getValue(String key){
return getValue(key, DEFAULT_REDIS_DB);
}
public static String getValue(String key, int db) {
if (StringUtils.isBlank(key)) {
return null;
}
Jedis jedis = getJedis();
String val = null;
try {
val = jedis.get(key);
} catch (JedisException e) {
log.error(e.getMessage(),e);
} catch (Exception e) {
log.error(e.getMessage(),e);
} finally {
if (jedis != null) {
jedis.close();
}
}
return val != null ? val : StringUtils.EMPTY;
}
public static String getHashFieldValue(String key, String field) {
return getHashFieldValue(key, field, DEFAULT_REDIS_DB);
}
/**
*
* 獲取Value Map 的值
*
* @since 1.0.0
*/
public static String getHashFieldValue(String key, String field, int db) {
if (StringUtils.isBlank(key) || StringUtils.isBlank(field)) {
return null;
}
Jedis jedis = getJedis();
String val = null;
try {
val = jedis.hget(key, field);
} catch (JedisException e) {
log.error(e.getMessage(),e);
} catch (Exception e) {
log.error(e.getMessage(),e);
} finally {
if (jedis != null) {
jedis.close();
}
}
return val;
}
/**
* 獲取field是否存在
* @param key key
* @param field field
* @param db db
* @return boolean
*/
public static boolean getHashFieldExist(String key, String field, int db) {
if (StringUtils.isBlank(key) || StringUtils.isBlank(field)) {
return false;
}
Jedis jedis = getJedis();
try {
return jedis.hexists(key, field);
} catch (Exception e) {
e.printStackTrace();
log.error(e.getMessage(),e);
} finally {
if (jedis != null) {
jedis.close();
}
}
return false;
}
public static Map<String, String> getHashAll(String key){
return getHashAll(key, DEFAULT_REDIS_DB);
}
public static Map<String, String> getHashAll(String key, int db) {
if (StringUtils.isBlank(key)) {
return null;
}
Jedis jedis = getJedis();
Map<String, String> val = null;
try {
val = jedis.hgetAll(key);
} catch (JedisException e) {
log.error(e.getMessage(),e);
} catch (Exception e) {
e.printStackTrace();
log.error(e.getMessage(),e);
} finally {
if (jedis != null) {
jedis.close();
}
}
return val == null ? new HashMap<String, String>() : val;
}
public static void delHashFiled(String key, String... fields) {
delHashFiled(key, DEFAULT_REDIS_DB, fields);
}
/**
*
* 刪除一個或多個field
*
* @since 1.0.0
*/
public static void delHashFiled(String key, int db, String... fields) {
if (StringUtils.isBlank(key) || fields == null || fields.length < 1) {
return;
}
Jedis jedis = getJedis();
try {
jedis.hdel(key, fields);
} catch (JedisException e) {
log.error(e.getMessage(),e);
} catch (Exception e) {
log.error(e.getMessage(),e);
} finally {
if (jedis != null) {
jedis.close();
}
}
}
public static void delKey(String... key) {
delKey(DEFAULT_REDIS_DB, key);
}
/**
*
* 刪除一個或多個key
*
* @since 1.0.0
*/
public static void delKey(int db, String... key) {
if (key == null || key.length < 1) {
return;
}
Jedis jedis = getJedis();
try {
// jedis.select(db);
jedis.del(key);
} catch (JedisException e) {
log.error(e.getMessage(),e);
} catch (Exception e) {
log.error(e.getMessage(),e);
} finally {
if (jedis != null) {
jedis.close();
}
}
}
/**
* 自增
* @param incr >0表示加 <0表示減
*/
public static Long hincr(String key, String field, Long incr, Integer expire) {
Long val = null;
Jedis jedis = getJedis();
try {
if(expire != null){
Long ttl = jedis.ttl(key);
val = jedis.hincrBy(key, field, incr);
if (val >= REDIS_INCR_MAX ) {//Integer無符號的最大數
jedis.set(key, "0");
}
if(ttl != null && ttl > 0){
jedis.expire(key, ttl.intValue());
}else{
jedis.expire(key, expire);
}
}else{
val = jedis.hincrBy(key, field, incr);
if (val >= REDIS_INCR_MAX ) {//Integer無符號的最大數
jedis.set(key, "0");
}
}
} catch (JedisException e) {
log.error(e.getMessage(),e);
} catch (Exception e) {
log.error(e.getMessage(),e);
} finally {
if (jedis != null) {
jedis.close();
}
}
return val;
}
/**
* 自增 1
* @return 返回操作后的結果
*/
public static Long incr(String key) {
Long val = null;
Jedis jedis = getJedis();
try {
// jedis.select(DEFAULT_REDIS_DB);
val = jedis.incr(key);
if (val >= REDIS_INCR_MAX ) {//Integer無符號的最大數
jedis.set(key, "0");
}
} catch (JedisException e) {
log.error(e.getMessage(),e);
} catch (Exception e) {
log.error(e.getMessage(),e);
} finally {
if (jedis != null) {
jedis.close();
}
}
return val;
}
/**
* 增加自定義步長
*/
public static Long incrBy(String key, Long incr) {
Long val = null;
Jedis jedis = getJedis();
try {
// jedis.select(DEFAULT_REDIS_DB);
val = jedis.incrBy(key,incr);
if (val >= REDIS_INCR_MAX ) {//Integer無符號的最大數
jedis.set(key, "0");
}
} catch (JedisException e) {
log.error(e.getMessage(),e);
} catch (Exception e) {
log.error(e.getMessage(),e);
} finally {
if (jedis != null) {
jedis.close();
}
}
return val;
}
/**
* 用於做原子鎖操作 HSETNX key field value
* 將哈希表 key 中的域 field 的值設置為 value ,當且僅當域 field 不存在。
* 若域 field 已經存在,該操作無效。
* 如果 key 不存在,一個新哈希表被創建並執行 HSETNX 命令。
* 設置成功,返回 1 。
如果給定域已經存在且沒有操作被執行,返回 0 。
*/
public static Long setValueIfNotExist(String key, String field, String value) {
Long val = 0L;
Jedis jedis = getJedis();
try {
int seconds = 3 * 60;//3min
// jedis.select(RedisLiveKeyConstants.LIVE_TEMP_DB);
Long ttl = jedis.ttl(key);
val = jedis.hsetnx(key, field, value);
if(val > 0){
jedis.expire(key, seconds);
}else{//防止設置過期時間失敗
if(ttl != null && (ttl == -1 || ttl > seconds)){
//獲得的是一個失效的key, 第一次還是失敗,第二次就好了
jedis.del(key);
}
}
} catch (JedisException e) {
log.error(e.getMessage(),e);
} catch (Exception e) {
log.error(e.getMessage(),e);
} finally {
if (jedis != null) {
jedis.close();
}
}
return val;
}
/**
* 將一個或多個 member 元素加入到集合 key 當中,已經存在於集合的 member 元素將被忽略。
假如 key 不存在,則創建一個只包含 member 元素作成員的集合。
當 key 不是集合類型時,返回一個錯誤。
* @param key
* @param members
* @return
*/
// public static Long sadd(String key, Integer expire, String... members) {
// return sadd(key, DEFAULT_REDIS_DB, expire, members);
// }
public static Long saddSet(String key,Integer expire, String... members){
Long val = null;
Jedis jedis = getJedis();
try {
if (members != null && members.length > 0) {
if(expire != null){
Long ttl = jedis.ttl(key);
val = jedis.sadd(key, members);
if(ttl != null && ttl > 0){
jedis.expire(key, ttl.intValue());
}else{
jedis.expire(key, expire);
}
}else{
val = jedis.sadd(key, members);
}
}
} catch (JedisException e) {
log.error(e.getMessage(),e);
} catch (Exception e) {
log.error(e.getMessage(),e);
} finally {
if (jedis != null) {
jedis.close();
}
}
return val;
}
/**
* 移除集合 key 中的一個或多個 member 元素,不存在的 member 元素會被忽略。
* @param key
* @param members
* @return
*/
public static Long sdel(String key, String... members) {
Long val = null;
Jedis jedis = getJedis();
try {
val = jedis.srem(key, members);
} catch (JedisException e) {
log.error(e.getMessage(),e);
} catch (Exception e) {
log.error(e.getMessage(),e);
} finally {
if (jedis != null) {
jedis.close();
}
}
return val;
}
/**
* 判斷 member 元素是否集合 key 的成員。
* true 存在
* @param key
* @param member
* @return
*/
public static boolean sismember(String key, String member) {
boolean val = false;
Jedis jedis = getJedis();
try {
// jedis.select(DEFAULT_REDIS_DB);
val = jedis.sismember(key, member);
} catch (JedisException e) {
log.error(e.getMessage(),e);
} catch (Exception e) {
log.error(e.getMessage(),e);
} finally {
if (jedis != null) {
jedis.close();
}
}
return val;
}
/**
* 返回集合 key 中的所有成員。不存在的 key 被視為空集合。
* @param key
* @return
*/
public static Set<String> smembers(String key) {
Set<String> val = null;
Jedis jedis = getJedis();
try {
// jedis.select(DEFAULT_REDIS_DB);
val = jedis.smembers(key);
} catch (JedisException e) {
log.error(e.getMessage(),e);
} catch (Exception e) {
log.error(e.getMessage(),e);
} finally {
if (jedis != null) {
jedis.close();
}
}
return val;
}
/**
* 返回集合隨機元素
* @param key
* @return
*/
public static List<String> srandom(String key,int num) {
List<String> list = new ArrayList<String>();
Jedis jedis = getJedis();
try {
list = jedis.srandmember(key,num);
} catch (JedisException e) {
log.error(e.getMessage(),e);
} catch (Exception e) {
log.error(e.getMessage(),e);
} finally {
if (jedis != null) {
jedis.close();
}
}
return list;
}
/**
* 移除集合 key 中的一個或多個 member 元素,不存在的 member 元素會被忽略。
* @param key
* @return
*/
public static Long slen(String key) {
Long val = null;
Jedis jedis = getJedis();
try {
val = jedis.scard(key);
} catch (JedisException e) {
log.error(e.getMessage(),e);
} catch (Exception e) {
log.error(e.getMessage(),e);
} finally {
if (jedis != null) {
jedis.close();
}
}
return val;
}
/**
* 移除並返回集合中的一個隨機元素。
* @param key
* @return
*/
public static String spop(String key) {
String val = null;
Jedis jedis = getJedis();
try {
val = jedis.spop(key);
} catch (JedisException e) {
log.error(e.getMessage(),e);
} catch (Exception e) {
log.error(e.getMessage(),e);
} finally {
if (jedis != null) {
jedis.close();
}
}
return val;
}
/**
* 檢查給定 key 是否存在。
* @param key
* @return
*/
public static boolean exists(String key) {
boolean val = false;
Jedis jedis = getJedis();
try {
val = jedis.exists(key);
} catch (JedisException e) {
log.error(e.getMessage(),e);
} catch (Exception e) {
log.error(e.getMessage(),e);
} finally {
if (jedis != null) {
jedis.close();
}
}
return val;
}
/**
* 將一個或多個值 value 插入到列表 key 的表尾(最右邊)。
* @param key
* @param value
* @return
*/
public static Long rpush(String key, Integer db, Integer expire, String... value) {
Long val = null;
Jedis jedis = getJedis();
try {
if(expire != null){
Long ttl = jedis.ttl(key);
val = jedis.rpush(key, value);
if(ttl != null && ttl > 0){
jedis.expire(key, ttl.intValue());
}else{
jedis.expire(key, expire);
}
}else{
val = jedis.rpush(key, value);
}
} catch (JedisException e) {
log.error(e.getMessage(),e);
} catch (Exception e) {
log.error(e.getMessage(),e);
} finally {
if (jedis != null) {
jedis.close();
}
}
return val;
}
/**
* 將一個或多個值 value 插入到列表 key 的表尾(最左邊)。
* @param key
* @param value
* @return
*/
public static Long lpush(String key, Integer db, Integer expire, String... value) {
Long val = null;
Jedis jedis = getJedis();
try {
if(expire != null){
Long ttl = jedis.ttl(key);
val = jedis.lpush(key, value);
if(ttl != null && ttl > 0){
jedis.expire(key, ttl.intValue());
}else{
jedis.expire(key, expire);
}
}else{
val = jedis.lpush(key, value);
}
} catch (JedisException e) {
log.error(e.getMessage(),e);
} catch (Exception e) {
log.error(e.getMessage(),e);
} finally {
if (jedis != null) {
jedis.close();
}
}
return val;
}
/**
* 列表修剪,讓列表只保留指定區間內的元素,不在指定區間之內的元素都將被刪除。
* @param key
* @param start
* @param stop
*/
public static void ltrim(String key, int start, int stop) {
Jedis jedis = getJedis();
try {
jedis.ltrim(key, start, stop);
} catch (JedisException e) {
log.error(e.getMessage(),e);
} catch (Exception e) {
log.error(e.getMessage(),e);
} finally {
if (jedis != null) {
jedis.close();
}
}
}
/**
* 將一個或多個值 value 彈出到列表 key 的表尾(最左邊)。
* @param key
* @param value
* @return
*/
public static String rpop(String key, Integer db) {
String val = null;
Jedis jedis = getJedis();
try {
val = jedis.rpop(key);
} catch (JedisException e) {
log.error(e.getMessage(),e);
} catch (Exception e) {
log.error(e.getMessage(),e);
} finally {
if (jedis != null) {
jedis.close();
}
}
return val;
}
/**
* 返回列表 key 中指定區間內的元素,區間以偏移量 start 和 stop 指定。
* @param key
* @param db
* @param start
* @param end
* @return
*/
public static List<String> lrange(String key, Integer db, long start, long end) {
List<String> val = null;
Jedis jedis = getJedis();
try {
val = jedis.lrange(key, start, end);
} catch (JedisException e) {
log.error(e.getMessage(),e);
} catch (Exception e) {
log.error(e.getMessage(),e);
} finally {
if (jedis != null) {
jedis.close();
}
}
return val;
}
/**
* 返回列表 key 的長度。
* @param key
* @param db
* @return
*/
public static Long llen(String key, Integer db){
Long val = null;
Jedis jedis = getJedis();
try {
val = jedis.llen(key);
} catch (JedisException e) {
log.error(e.getMessage(),e);
} catch (Exception e) {
log.error(e.getMessage(),e);
} finally {
if (jedis != null) {
jedis.close();
}
}
return val == null?0:val;
}
/**
* 返回列表 key 的長度。
* @param key
* @param db
* @return
*/
public static Long hlen(String key){
Long val = null;
Jedis jedis = getJedis();
try {
val = jedis.hlen(key);
} catch (JedisException e) {
log.error(e.getMessage(),e);
} catch (Exception e) {
log.error(e.getMessage(),e);
} finally {
if (jedis != null) {
jedis.close();
}
}
return val == null?0:val;
}
/**
* 設置過期時間
* @param key
* @return
*/
public static Integer ttl(String key){
if(StringUtils.isBlank(key)) {
return -2;
}
Jedis jedis = getJedis();
Long val = -2L;
try {
val = jedis.ttl(key);
} catch (JedisException e) {
log.error(e.getMessage(),e);
} catch (Exception e) {
log.error(e.getMessage(),e);
} finally {
if (jedis != null) {
jedis.close();
}
}
return val.intValue();
}
/**
* HyperLogLog add
* @param key
* @return
*/
public static Integer pfadd(String key, String... elements){
if(StringUtils.isBlank(key)) {
return -2;
}
Jedis jedis = getJedis();
Long val = -2L;
try {
val = jedis.pfadd(key, elements);
} catch (JedisException e) {
log.error(e.getMessage(),e);
} catch (Exception e) {
log.error(e.getMessage(),e);
} finally {
if (jedis != null) {
jedis.close();
}
}
return val.intValue();
}
/**
* HyperLogLog count
* @param key
* @return
*/
public static Long pfcount(String key){
if(StringUtils.isBlank(key)) {
return 0L;
}
Jedis jedis = getJedis();
Long val = 0L;
try {
val = jedis.pfcount(key);
} catch (JedisException e) {
log.error(e.getMessage(),e);
} catch (Exception e) {
log.error(e.getMessage(),e);
} finally {
if (jedis != null) {
jedis.close();
}
}
return val;
}
/**
* 更新直播間最后瀏覽時間
* @param userId
* @param liveId
* @return
*/
public static Long zaddLastBrowse(String userId, String liveId, Date date){
if(QlchatUtil.isEmpty(userId) || QlchatUtil.isEmpty(liveId)){
return null;
}
String cacheKey = "LAST_BROWSE_".concat(userId);
double score = date.getTime();
return zadd(cacheKey, liveId, score);
}
/**
* 按照score遞減分頁獲取最新瀏覽的liveId
* @param userId
* @param start
* @param end
* @return
*/
public static Set<String> zrevRangeLastBrowse(String userId, int pageNum, int pageSize){
if(QlchatUtil.isEmpty(userId)){
return null;
}
int start = (pageNum - 1) * pageSize;
int end = start + pageSize - 1;
String cacheKey = "LAST_BROWSE_".concat(userId);
return zrevrange(cacheKey, start, end);
}
public static Long zcardLastBrowse(String userId){
if(QlchatUtil.isEmpty(userId)){
return null;
}
String cacheKey = "LAST_BROWSE_".concat(userId);
return zcard(cacheKey);
}
public static Long zremLastBrowse(String userId){
if(QlchatUtil.isEmpty(userId)){
return null;
}
String cacheKey = "LAST_BROWSE_".concat(userId);
Long countNum = zcard(cacheKey);
if(countNum > 60){
return zremrangeByRank(cacheKey, 0, (countNum.intValue() - 60));
}
return null;
}
}
redis分布式鎖工具類
package com.qlchat.redis.cache;
import com.qlchat.common.constants.CommonConstants;
import com.qlchat.common.constants.RedisLiveKeyConstants;
import com.qlchat.common.helper.*;
import com.qlchat.component.redis.template.*;
public class PublicLock {
private static final Long TOTAL_WAIT_SENCODS = 10 * 1000L;// 10s獲取不到算超時
private static final Integer REPLY_WAIT_SENCODS = 5;// 重試獲取鎖間隔時間ms
public static ValueRedisTemplate valueRedisTemplate;
public static HashRedisTemplate hashRedisTemplate;
public static ListRedisTemplate listRedisTemplate;
public static SetRedisTemplate setRedisTemplate;
public static HyperLogLogTemplate hyperLogLogTemplate;
static {
valueRedisTemplate = SpringHelper.getBean(ValueRedisTemplate.class);
hashRedisTemplate = SpringHelper.getBean(HashRedisTemplate.class);
listRedisTemplate = SpringHelper.getBean(ListRedisTemplate.class);
setRedisTemplate = SpringHelper.getBean(SetRedisTemplate.class);
hyperLogLogTemplate = SpringHelper.getBean(HyperLogLogTemplate.class);
}
/**
* 獲取操作鎖
* 需要寫線程去過時歷史失敗的鎖
* @return true 獲取成功,false獲取失敗
* @throws InterruptedException
*/
public static boolean getLock(String lockKey, Long waitSencods) throws InterruptedException{
long t1 = System.currentTimeMillis();
boolean isSuccess = false;
while(!isSuccess){
if (System.currentTimeMillis() <= t1 + waitSencods) {
isSuccess = tryLock(lockKey, lockKey);
if(!isSuccess){
Thread.sleep(REPLY_WAIT_SENCODS);//sleep10ms
}
}else{//超過等待時間,返回失敗
break;
}
}
return isSuccess;
}
/**
* 獲取操作鎖
* @return true 獲取成功,false獲取失敗
* @throws InterruptedException
*/
public static boolean getLock(String lockKey) throws InterruptedException{
Long waitSencods = TOTAL_WAIT_SENCODS;
return getLock(lockKey, waitSencods);
}
/**
* 釋放鎖
*/
public static void freeLock(String lockKey){
BaseCache.delKey(RedisLiveKeyConstants.LIVE_TEMP_DB, lockKey);
}
/**
* 鎖是否存在
* @param lockKey
* @return
*/
public static boolean isLock(String lockKey) {
return BaseCache.getHashFieldExist(lockKey, lockKey, 0);
}
/**
* 嘗試獲取鎖
* @return
*/
private static boolean tryLock(String lockKey, String field){
boolean isSuccess = false;
long setValue = BaseCache.setValueIfNotExist(lockKey, field, CommonConstants.YesOrNo.YES);//返回1則成功
if(setValue > 0){
isSuccess = true;
}
return isSuccess;
}
}
