Commit 88f90166 authored by 杨锐's avatar 杨锐

redis分布式锁,处理/user/center/save/userExtInfo并发问题,导致MySQLIntegrityConstraintViolationException

parent e4e73cce
package cn.quantgroup.xyqb.util; package cn.quantgroup.xyqb.util;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.text.RandomStringGenerator; import org.apache.commons.text.RandomStringGenerator;
import org.springframework.dao.InvalidDataAccessResourceUsageException; import org.springframework.dao.InvalidDataAccessResourceUsageException;
import org.springframework.data.redis.core.RedisCallback; import org.springframework.data.redis.core.RedisCallback;
...@@ -17,14 +18,14 @@ import java.util.Random; ...@@ -17,14 +18,14 @@ import java.util.Random;
* // CODE * // CODE
* } * }
* } catch (InterruptedException e) { * } catch (InterruptedException e) {
* LOGGER.warn("获取锁失败:lockKey:{},exception:{}",redisLock.getLockKey(),e.getMessage()); * log.warn("获取锁失败:lockKey:{},exception:{}",redisLock.getLockKey(),e.getMessage());
* }finally { * }finally {
* redisLock.unlock(); * redisLock.unlock();
* } * }
* </pre> * </pre>
*/ */
@Slf4j
public class RedisLock { public class RedisLock {
private final static org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(RedisLock.class);
private RedisTemplate redisTemplate; private RedisTemplate redisTemplate;
/** /**
* Lock key path. * Lock key path.
...@@ -56,7 +57,7 @@ public class RedisLock { ...@@ -56,7 +57,7 @@ public class RedisLock {
public RedisLock(RedisTemplate redisTemplate, String lockKey) { public RedisLock(RedisTemplate redisTemplate, String lockKey) {
this.redisTemplate = redisTemplate; this.redisTemplate = redisTemplate;
this.lockKey = "lock:".concat(lockKey).concat("_lock"); this.lockKey = "lock:".concat(lockKey).concat("_lock");
logger.info("准备锁 lock:{},{}", getLockKey()); log.info("准备锁 lock:{},{}", getLockKey());
} }
/** /**
...@@ -107,7 +108,7 @@ public class RedisLock { ...@@ -107,7 +108,7 @@ public class RedisLock {
return serializer.deserialize(data); return serializer.deserialize(data);
}); });
} catch (Exception e) { } catch (Exception e) {
logger.error("get redis error, key " + key + ": {}", e); log.error("get redis error, key " + key + ": {}", e);
throw new InvalidDataAccessResourceUsageException(e.getMessage()); throw new InvalidDataAccessResourceUsageException(e.getMessage());
} }
return obj != null ? obj.toString() : null; return obj != null ? obj.toString() : null;
...@@ -134,7 +135,7 @@ public class RedisLock { ...@@ -134,7 +135,7 @@ public class RedisLock {
return success; return success;
}); });
} catch (Exception e) { } catch (Exception e) {
logger.error("setNX redis error, key “" + key + "”: {}", e); log.error("setNX redis error, key “" + key + "”: {}", e);
} }
return obj != null ? (Boolean) obj : false; return obj != null ? (Boolean) obj : false;
} }
...@@ -156,7 +157,7 @@ public class RedisLock { ...@@ -156,7 +157,7 @@ public class RedisLock {
return serializer.deserialize(ret); return serializer.deserialize(ret);
}); });
} catch (Exception e) { } catch (Exception e) {
logger.error("getSet redis error, key : {}", key); log.error("getSet redis error, key : {}", key);
} }
return obj != null ? (String) obj : null; return obj != null ? (String) obj : null;
} }
...@@ -179,7 +180,7 @@ public class RedisLock { ...@@ -179,7 +180,7 @@ public class RedisLock {
if (this.setNX(lockKey, expiresStr)) { if (this.setNX(lockKey, expiresStr)) {
// lock acquired // lock acquired
this.expiresStr = expiresStr; this.expiresStr = expiresStr;
logger.info("获取锁成功 lock:{}", getLockKey()); log.info("获取锁成功 lock:{}", getLockKey());
return true; return true;
} }
...@@ -199,7 +200,7 @@ public class RedisLock { ...@@ -199,7 +200,7 @@ public class RedisLock {
//[分布式的情况下]:如过这个时候,多个线程恰好都到了这里,但是只有一个线程的设置值和当前值相同,他才有权利获取锁 //[分布式的情况下]:如过这个时候,多个线程恰好都到了这里,但是只有一个线程的设置值和当前值相同,他才有权利获取锁
// lock acquired // lock acquired
this.expiresStr = expiresStr; this.expiresStr = expiresStr;
logger.info("获取锁成功(前一个锁超时) lock:{}", getLockKey()); log.info("获取锁成功(前一个锁超时) lock:{}", getLockKey());
return true; return true;
} }
} }
...@@ -213,8 +214,8 @@ public class RedisLock { ...@@ -213,8 +214,8 @@ public class RedisLock {
Thread.sleep(sleepTime); Thread.sleep(sleepTime);
} catch (InvalidDataAccessResourceUsageException e) { } catch (InvalidDataAccessResourceUsageException e) {
if (retryCount > 3) { if (retryCount > 3) {
logger.error("redis有可能出现问题不能获取lockKey:{}", lockKey); log.error("redis有可能出现问题不能获取lockKey:{}", lockKey);
logger.warn("redis lock 3次重试仍异常,lockKey: {} 进行降级服务....", lockKey); log.warn("redis lock 3次重试仍异常,lockKey: {} 进行降级服务....", lockKey);
return true; return true;
} }
retryCount++; retryCount++;
...@@ -225,7 +226,7 @@ public class RedisLock { ...@@ -225,7 +226,7 @@ public class RedisLock {
Thread.sleep(100); } Thread.sleep(100); }
} }
} }
logger.info("锁失败 lock:{}", getLockKey()); log.info("锁失败 lock:{}", getLockKey());
return false; return false;
} }
...@@ -240,18 +241,18 @@ public class RedisLock { ...@@ -240,18 +241,18 @@ public class RedisLock {
try { try {
expStr = this.get(lockKey); expStr = this.get(lockKey);
} catch (InvalidDataAccessResourceUsageException e) { } catch (InvalidDataAccessResourceUsageException e) {
logger.warn("redis unlock 异常, lockKey:{} 进行降级服务....", lockKey); log.warn("redis unlock 异常, lockKey:{} 进行降级服务....", lockKey);
} }
if (expStr == null || this.expiresStr.equals(expStr)) { if (expStr == null || this.expiresStr.equals(expStr)) {
redisTemplate.delete(lockKey); redisTemplate.delete(lockKey);
logger.info("解锁成功 lock:{}", getLockKey()); log.info("解锁成功 lock:{}", getLockKey());
return; return;
} }
} catch (Exception e) { } catch (Exception e) {
logger.error("redis unlock 异常 lockKey "+lockKey+":{} ", e); log.error("redis unlock 异常 lockKey "+lockKey+":{} ", e);
} }
} }
logger.warn("没有锁或者因非本对象产生的锁,不能进行解锁,因为是不安全的"); log.warn("没有锁或者因非本对象产生的锁,不能进行解锁,因为是不安全的");
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment