From c550a7f3441ae2a764c7a4c2a85cc1f2321e3bce Mon Sep 17 00:00:00 2001 From: songtj <17679089594@163.com> Date: Fri, 20 Oct 2023 22:30:04 +0800 Subject: [PATCH 1/2] =?UTF-8?q?:art:=20=E4=BC=98=E5=8C=96@Cached=E5=9C=A8?= =?UTF-8?q?=E5=B9=B6=E5=8F=91=E4=B8=8B=E8=BF=94=E5=9B=9Enull=E7=9A=84?= =?UTF-8?q?=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../common/redis/core/CacheStringAspect.java | 15 +++++++++++---- .../common/redis/core/annotation/Cached.java | 9 +++++++++ .../ballcat/common/redis/operation/CachedOps.java | 13 ++++++++++++- 3 files changed, 32 insertions(+), 5 deletions(-) diff --git a/ballcat-common/ballcat-common-redis/src/main/java/com/hccake/ballcat/common/redis/core/CacheStringAspect.java b/ballcat-common/ballcat-common-redis/src/main/java/com/hccake/ballcat/common/redis/core/CacheStringAspect.java index 115a04bb..a7a776f3 100644 --- a/ballcat-common/ballcat-common-redis/src/main/java/com/hccake/ballcat/common/redis/core/CacheStringAspect.java +++ b/ballcat-common/ballcat-common-redis/src/main/java/com/hccake/ballcat/common/redis/core/CacheStringAspect.java @@ -7,6 +7,7 @@ import com.hccake.ballcat.common.redis.core.annotation.CacheDels; import com.hccake.ballcat.common.redis.core.annotation.CachePut; import com.hccake.ballcat.common.redis.core.annotation.Cached; import com.hccake.ballcat.common.redis.lock.DistributedLock; +import com.hccake.ballcat.common.redis.lock.StateHandler; import com.hccake.ballcat.common.redis.operation.CacheDelOps; import com.hccake.ballcat.common.redis.operation.CacheDelsOps; import com.hccake.ballcat.common.redis.operation.CachePutOps; @@ -91,8 +92,8 @@ public class CacheStringAspect { // 失效时间控制 Consumer cachePut = prodCachePutFunction(valueOperations, key, cachedAnnotation.ttl(), cachedAnnotation.timeUnit()); - return cached(new CachedOps(point, lockKey, cacheQuery, cachePut, method.getGenericReturnType())); - + int failRetries = cachedAnnotation.failRetries(); + return cached(new CachedOps(point, lockKey, cacheQuery, cachePut, method.getGenericReturnType(), failRetries)); } // 缓存更新处理 @@ -165,7 +166,7 @@ public class CacheStringAspect { } // 2.==========如果缓存为空 则需查询数据库并更新=============== - cacheData = DistributedLock.instance().action(ops.lockKey(), () -> { + StateHandler handler = DistributedLock.instance().action(ops.lockKey(), () -> { String cacheValue = cacheQuery.get(); if (cacheValue == null) { // 从数据库查询数据 @@ -176,7 +177,13 @@ public class CacheStringAspect { ops.cachePut().accept(cacheValue); } return cacheValue; - }).onLockFail(cacheQuery).lock(); + }).onLockFail(cacheQuery); + + int failRetries = ops.failRetries(); + do { + cacheData = handler.lock(); + } while (cacheData == null && failRetries-- != 0); + // 自旋时间内未获取到锁,或者数据库中数据为空,返回null if (cacheData == null || ops.nullValue(cacheData)) { return null; diff --git a/ballcat-common/ballcat-common-redis/src/main/java/com/hccake/ballcat/common/redis/core/annotation/Cached.java b/ballcat-common/ballcat-common-redis/src/main/java/com/hccake/ballcat/common/redis/core/annotation/Cached.java index 793a4b13..4ecde887 100644 --- a/ballcat-common/ballcat-common-redis/src/main/java/com/hccake/ballcat/common/redis/core/annotation/Cached.java +++ b/ballcat-common/ballcat-common-redis/src/main/java/com/hccake/ballcat/common/redis/core/annotation/Cached.java @@ -35,4 +35,13 @@ public @interface Cached { */ TimeUnit timeUnit() default TimeUnit.SECONDS; + /** + * 失败重试次数 + * 小于0: 无限重试 + * 等于0: 不重试 + * 大于0: 重试次数 + * + * @return + */ + int failRetries() default 20; } diff --git a/ballcat-common/ballcat-common-redis/src/main/java/com/hccake/ballcat/common/redis/operation/CachedOps.java b/ballcat-common/ballcat-common-redis/src/main/java/com/hccake/ballcat/common/redis/operation/CachedOps.java index 60699a6c..c9ec3e2c 100644 --- a/ballcat-common/ballcat-common-redis/src/main/java/com/hccake/ballcat/common/redis/operation/CachedOps.java +++ b/ballcat-common/ballcat-common-redis/src/main/java/com/hccake/ballcat/common/redis/operation/CachedOps.java @@ -33,6 +33,11 @@ public class CachedOps extends AbstractCacheOps { */ private final Consumer cachePut; + /** + * 从Redis中获取缓存数据的失败时的重试次数 + */ + private final int failRetries; + /** * 基本构造函数 * @param joinPoint 织入方法 @@ -40,14 +45,16 @@ public class CachedOps extends AbstractCacheOps { * @param cacheQuery 查询缓存函数 * @param cachePut 更新缓存函数 * @param returnType 返回数据类型 + * @param failRetries 查询缓存函数执行失败时的重试次数 */ public CachedOps(ProceedingJoinPoint joinPoint, String lockKey, Supplier cacheQuery, - Consumer cachePut, Type returnType) { + Consumer cachePut, Type returnType, int failRetries) { super(joinPoint); this.lockKey = lockKey; this.cacheQuery = cacheQuery; this.cachePut = cachePut; this.returnType = returnType; + this.failRetries = failRetries; } public Supplier cacheQuery() { @@ -66,4 +73,8 @@ public class CachedOps extends AbstractCacheOps { return lockKey; } + public int failRetries(){ + return failRetries; + } + } -- Gitee From 5e8eddf1aebff1ae72af551c688dcc8ad13ce330 Mon Sep 17 00:00:00 2001 From: songtj <17679089594@163.com> Date: Sat, 21 Oct 2023 12:03:30 +0800 Subject: [PATCH 2/2] =?UTF-8?q?:art:=20=E9=87=8D=E5=91=BD=E5=90=8D?= =?UTF-8?q?=E9=94=81=E7=AB=9E=E4=BA=89=E5=A4=B1=E8=B4=A5=E9=87=8D=E8=AF=95?= =?UTF-8?q?=E7=9A=84=E5=B8=B8=E9=87=8F=E5=90=8D;=E4=BF=AE=E6=94=B9?= =?UTF-8?q?=E9=BB=98=E8=AE=A4=E9=87=8D=E8=AF=95=E6=AC=A1=E6=95=B0;?= =?UTF-8?q?=E8=87=AA=E6=97=8B=E6=97=B6=E6=B7=BB=E5=8A=A0=E7=BA=BF=E7=A8=8B?= =?UTF-8?q?=E7=9D=A1=E7=9C=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../common/redis/core/CacheStringAspect.java | 16 +++------- .../common/redis/core/annotation/Cached.java | 9 ++---- .../common/redis/lock/DistributedLock.java | 31 +++++++++++++++++-- .../common/redis/lock/StateHandler.java | 6 ++++ .../common/redis/operation/CachedOps.java | 14 ++++----- 5 files changed, 50 insertions(+), 26 deletions(-) diff --git a/ballcat-common/ballcat-common-redis/src/main/java/com/hccake/ballcat/common/redis/core/CacheStringAspect.java b/ballcat-common/ballcat-common-redis/src/main/java/com/hccake/ballcat/common/redis/core/CacheStringAspect.java index a7a776f3..79aaa5c1 100644 --- a/ballcat-common/ballcat-common-redis/src/main/java/com/hccake/ballcat/common/redis/core/CacheStringAspect.java +++ b/ballcat-common/ballcat-common-redis/src/main/java/com/hccake/ballcat/common/redis/core/CacheStringAspect.java @@ -7,7 +7,6 @@ import com.hccake.ballcat.common.redis.core.annotation.CacheDels; import com.hccake.ballcat.common.redis.core.annotation.CachePut; import com.hccake.ballcat.common.redis.core.annotation.Cached; import com.hccake.ballcat.common.redis.lock.DistributedLock; -import com.hccake.ballcat.common.redis.lock.StateHandler; import com.hccake.ballcat.common.redis.operation.CacheDelOps; import com.hccake.ballcat.common.redis.operation.CacheDelsOps; import com.hccake.ballcat.common.redis.operation.CachePutOps; @@ -92,8 +91,9 @@ public class CacheStringAspect { // 失效时间控制 Consumer cachePut = prodCachePutFunction(valueOperations, key, cachedAnnotation.ttl(), cachedAnnotation.timeUnit()); - int failRetries = cachedAnnotation.failRetries(); - return cached(new CachedOps(point, lockKey, cacheQuery, cachePut, method.getGenericReturnType(), failRetries)); + int retryCount = cachedAnnotation.retryCount(); + return cached( + new CachedOps(point, lockKey, cacheQuery, cachePut, method.getGenericReturnType(), retryCount)); } // 缓存更新处理 @@ -166,7 +166,7 @@ public class CacheStringAspect { } // 2.==========如果缓存为空 则需查询数据库并更新=============== - StateHandler handler = DistributedLock.instance().action(ops.lockKey(), () -> { + cacheData = DistributedLock.instance().action(ops.lockKey(), () -> { String cacheValue = cacheQuery.get(); if (cacheValue == null) { // 从数据库查询数据 @@ -177,13 +177,7 @@ public class CacheStringAspect { ops.cachePut().accept(cacheValue); } return cacheValue; - }).onLockFail(cacheQuery); - - int failRetries = ops.failRetries(); - do { - cacheData = handler.lock(); - } while (cacheData == null && failRetries-- != 0); - + }).onLockFail(cacheQuery).retryCount(ops.retryCount()).lock(); // 自旋时间内未获取到锁,或者数据库中数据为空,返回null if (cacheData == null || ops.nullValue(cacheData)) { return null; diff --git a/ballcat-common/ballcat-common-redis/src/main/java/com/hccake/ballcat/common/redis/core/annotation/Cached.java b/ballcat-common/ballcat-common-redis/src/main/java/com/hccake/ballcat/common/redis/core/annotation/Cached.java index 4ecde887..98da17d8 100644 --- a/ballcat-common/ballcat-common-redis/src/main/java/com/hccake/ballcat/common/redis/core/annotation/Cached.java +++ b/ballcat-common/ballcat-common-redis/src/main/java/com/hccake/ballcat/common/redis/core/annotation/Cached.java @@ -36,12 +36,9 @@ public @interface Cached { TimeUnit timeUnit() default TimeUnit.SECONDS; /** - * 失败重试次数 - * 小于0: 无限重试 - * 等于0: 不重试 - * 大于0: 重试次数 - * + * 锁竞争失败时的重试次数 小于0: 无限重试 等于0: 不重试 大于0: 重试次数 * @return */ - int failRetries() default 20; + int retryCount() default 5; + } diff --git a/ballcat-common/ballcat-common-redis/src/main/java/com/hccake/ballcat/common/redis/lock/DistributedLock.java b/ballcat-common/ballcat-common-redis/src/main/java/com/hccake/ballcat/common/redis/lock/DistributedLock.java index 9670f32d..00a17011 100644 --- a/ballcat-common/ballcat-common-redis/src/main/java/com/hccake/ballcat/common/redis/lock/DistributedLock.java +++ b/ballcat-common/ballcat-common-redis/src/main/java/com/hccake/ballcat/common/redis/lock/DistributedLock.java @@ -1,5 +1,6 @@ package com.hccake.ballcat.common.redis.lock; +import cn.hutool.core.thread.ThreadUtil; import com.hccake.ballcat.common.redis.lock.function.ExceptionHandler; import com.hccake.ballcat.common.redis.lock.function.ThrowingExecutor; import org.springframework.util.Assert; @@ -24,6 +25,8 @@ public final class DistributedLock implements Action, StateHandler { TimeUnit timeUnit; + int retryCount; + ThrowingExecutor executeAction; UnaryOperator successAction; @@ -71,12 +74,18 @@ public final class DistributedLock implements Action, StateHandler { return this; } + @Override + public StateHandler retryCount(int retryCount) { + this.retryCount = retryCount; + return this; + } + @Override public T lock() { String requestId = UUID.randomUUID().toString(); + boolean exResolved = false; if (Boolean.TRUE.equals(CacheLock.lock(this.key, requestId, this.timeout, this.timeUnit))) { T value = null; - boolean exResolved = false; try { value = executeAction.execute(); this.result = value; @@ -92,7 +101,13 @@ public final class DistributedLock implements Action, StateHandler { this.result = this.successAction.apply(value); } } - else if (lockFailAction != null) { + if (lockFailAction != null) { + this.result = lockFailAction.get(); + } + int fib = 3; + while (this.result == null && lockFailAction != null && !exResolved && retryCount-- != 0) { + // 使用斐波那契数列进行睡眠时间的增长 + ThreadUtil.safeSleep(calculateFibonacci(fib++) * 10); this.result = lockFailAction.get(); } return this.result; @@ -103,4 +118,16 @@ public final class DistributedLock implements Action, StateHandler { throw (E) t; } + /** + * 计算斐波那契值 + * @param fib + * @return + */ + public int calculateFibonacci(int fib) { + if (fib <= 0 || fib == 1 || fib == 2) { + return 1; + } + return calculateFibonacci(fib - 1) + calculateFibonacci(fib - 2); + } + } diff --git a/ballcat-common/ballcat-common-redis/src/main/java/com/hccake/ballcat/common/redis/lock/StateHandler.java b/ballcat-common/ballcat-common-redis/src/main/java/com/hccake/ballcat/common/redis/lock/StateHandler.java index 5654af63..406e8008 100644 --- a/ballcat-common/ballcat-common-redis/src/main/java/com/hccake/ballcat/common/redis/lock/StateHandler.java +++ b/ballcat-common/ballcat-common-redis/src/main/java/com/hccake/ballcat/common/redis/lock/StateHandler.java @@ -32,6 +32,12 @@ public interface StateHandler { */ StateHandler onException(ExceptionHandler action); + /** + * 控制锁竞争失败时的重试次数 + * @param retryCount + */ + StateHandler retryCount(int retryCount); + /** * 终态,获取锁 * @return result diff --git a/ballcat-common/ballcat-common-redis/src/main/java/com/hccake/ballcat/common/redis/operation/CachedOps.java b/ballcat-common/ballcat-common-redis/src/main/java/com/hccake/ballcat/common/redis/operation/CachedOps.java index c9ec3e2c..3c995c17 100644 --- a/ballcat-common/ballcat-common-redis/src/main/java/com/hccake/ballcat/common/redis/operation/CachedOps.java +++ b/ballcat-common/ballcat-common-redis/src/main/java/com/hccake/ballcat/common/redis/operation/CachedOps.java @@ -34,9 +34,9 @@ public class CachedOps extends AbstractCacheOps { private final Consumer cachePut; /** - * 从Redis中获取缓存数据的失败时的重试次数 + * 在Redis中锁竞争失败时的重试次数 */ - private final int failRetries; + private final int retryCount; /** * 基本构造函数 @@ -45,16 +45,16 @@ public class CachedOps extends AbstractCacheOps { * @param cacheQuery 查询缓存函数 * @param cachePut 更新缓存函数 * @param returnType 返回数据类型 - * @param failRetries 查询缓存函数执行失败时的重试次数 + * @param retryCount 锁竞争失败时的重试次数 */ public CachedOps(ProceedingJoinPoint joinPoint, String lockKey, Supplier cacheQuery, - Consumer cachePut, Type returnType, int failRetries) { + Consumer cachePut, Type returnType, int retryCount) { super(joinPoint); this.lockKey = lockKey; this.cacheQuery = cacheQuery; this.cachePut = cachePut; this.returnType = returnType; - this.failRetries = failRetries; + this.retryCount = retryCount; } public Supplier cacheQuery() { @@ -73,8 +73,8 @@ public class CachedOps extends AbstractCacheOps { return lockKey; } - public int failRetries(){ - return failRetries; + public int retryCount() { + return retryCount; } } -- Gitee