From bc12b4c3b1b3ef89669ea2201c75651eb4987c90 Mon Sep 17 00:00:00 2001 From: "1437892690@qq.com" <1437892690@qq.com> Date: Fri, 23 May 2025 11:13:04 +0800 Subject: [PATCH 1/2] =?UTF-8?q?[=E5=8A=9F=E8=83=BD]=20=E5=A2=9E=E5=8A=A0?= =?UTF-8?q?=E4=B8=80=E4=B8=AA=E5=8F=AF=E4=BB=A5=E5=9C=A8=E9=AB=98=E5=B9=B6?= =?UTF-8?q?=E5=8F=91=E5=9C=BA=E6=99=AF=E4=B8=8B=E9=98=B2=E6=AD=A2=E8=A2=AB?= =?UTF-8?q?=E5=87=BB=E7=A9=BF=E7=9A=84Mybaties=E4=BA=8C=E7=BA=A7=E7=BC=93?= =?UTF-8?q?=E5=AD=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 关联 #[1421727635046400]增加一个可以在高并发场景下防止被击穿的Mybaties二级缓存 http://192.168.0.96:8090/demo/rdm.html#/story-detail/939050947543040/939050947543042/1421727635046400 --- .../framework/dao/cache/NeatLogicConcurrentSafeCache.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/neatlogic/framework/dao/cache/NeatLogicConcurrentSafeCache.java b/src/main/java/neatlogic/framework/dao/cache/NeatLogicConcurrentSafeCache.java index 3784cca93..32abe16a9 100644 --- a/src/main/java/neatlogic/framework/dao/cache/NeatLogicConcurrentSafeCache.java +++ b/src/main/java/neatlogic/framework/dao/cache/NeatLogicConcurrentSafeCache.java @@ -103,7 +103,7 @@ public class NeatLogicConcurrentSafeCache implements Cache { if (CollectionUtils.isNotEmpty(keys)) { for (Object key : keys) { ReentrantLock lock = LOCAL_LOCK_MAP.remove(generateLockKey(getId(), key)); - if (lock != null && lock.isLocked()) { + if (lock != null && lock.isLocked() && lock.isHeldByCurrentThread()) { lock.unlock(); } } @@ -135,7 +135,7 @@ public class NeatLogicConcurrentSafeCache implements Cache { } cachedElement = getCache().get(key); if (cachedElement != null) { - if (lock.isLocked()) { + if (lock.isLocked() && lock.isHeldByCurrentThread()) { lock.unlock(); } return cachedElement.getObjectValue(); @@ -158,7 +158,7 @@ public class NeatLogicConcurrentSafeCache implements Cache { public void putObject(Object key, Object value) { getCache().put(new Element(key, value)); ReentrantLock lock = LOCAL_LOCK_MAP.remove(generateLockKey(getId(), key)); - if (lock != null) { + if (lock != null && lock.isLocked() && lock.isHeldByCurrentThread()) { lock.unlock(); } } @@ -171,7 +171,7 @@ public class NeatLogicConcurrentSafeCache implements Cache { Object obj = getObject(key); getCache().remove(key); ReentrantLock lock = LOCAL_LOCK_MAP.remove(generateLockKey(getId(), key)); - if (lock != null) { + if (lock != null && lock.isLocked() && lock.isHeldByCurrentThread()) { lock.unlock(); } return obj; -- Gitee From b63cd7519f17ce44b1e82ce6c4845ced9e33d488 Mon Sep 17 00:00:00 2001 From: "1437892690@qq.com" <1437892690@qq.com> Date: Fri, 23 May 2025 19:06:14 +0800 Subject: [PATCH 2/2] =?UTF-8?q?[=E5=8A=9F=E8=83=BD]=20=E5=A2=9E=E5=8A=A0?= =?UTF-8?q?=E4=B8=80=E4=B8=AA=E5=8F=AF=E4=BB=A5=E5=9C=A8=E9=AB=98=E5=B9=B6?= =?UTF-8?q?=E5=8F=91=E5=9C=BA=E6=99=AF=E4=B8=8B=E9=98=B2=E6=AD=A2=E8=A2=AB?= =?UTF-8?q?=E5=87=BB=E7=A9=BF=E7=9A=84Mybaties=E4=BA=8C=E7=BA=A7=E7=BC=93?= =?UTF-8?q?=E5=AD=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 关联 #[1421727635046400]增加一个可以在高并发场景下防止被击穿的Mybaties二级缓存 http://192.168.0.96:8090/demo/rdm.html#/story-detail/939050947543040/939050947543042/1421727635046400 --- .../cache/NeatLogicConcurrentSafeCache.java | 108 +++++++----------- 1 file changed, 42 insertions(+), 66 deletions(-) diff --git a/src/main/java/neatlogic/framework/dao/cache/NeatLogicConcurrentSafeCache.java b/src/main/java/neatlogic/framework/dao/cache/NeatLogicConcurrentSafeCache.java index 32abe16a9..8d8308263 100644 --- a/src/main/java/neatlogic/framework/dao/cache/NeatLogicConcurrentSafeCache.java +++ b/src/main/java/neatlogic/framework/dao/cache/NeatLogicConcurrentSafeCache.java @@ -24,11 +24,13 @@ import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang3.StringUtils; import org.apache.ibatis.cache.Cache; +import java.util.ArrayList; import java.util.List; +import java.util.Map; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.Semaphore; import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.ReadWriteLock; -import java.util.concurrent.locks.ReentrantLock; /** * 高并发场景下,防止缓存击穿 @@ -38,7 +40,7 @@ public class NeatLogicConcurrentSafeCache implements Cache { * The cache manager reference. */ protected static CacheManager CACHE_MANAGER = CacheManager.create(); - private final static ConcurrentHashMap LOCAL_LOCK_MAP = new ConcurrentHashMap<>(); + private final static ConcurrentHashMap LOCAL_LOCK_MAP = new ConcurrentHashMap<>(); private static String generateLockKey(String id, Object key) { String tenant = null; @@ -99,15 +101,16 @@ public class NeatLogicConcurrentSafeCache implements Cache { public void clear() { Ehcache cache = getCache(); List keys = cache.getKeys(); - cache.removeAll(); if (CollectionUtils.isNotEmpty(keys)) { for (Object key : keys) { - ReentrantLock lock = LOCAL_LOCK_MAP.remove(generateLockKey(getId(), key)); - if (lock != null && lock.isLocked() && lock.isHeldByCurrentThread()) { - lock.unlock(); + String lockKey = generateLockKey(getId(), key); + Semaphore lock = LOCAL_LOCK_MAP.remove(lockKey); + if (lock != null) { + lock.release(); } } } + cache.removeAll(); } /** @@ -127,16 +130,27 @@ public class NeatLogicConcurrentSafeCache implements Cache { if (cachedElement != null) { return cachedElement.getObjectValue(); } - ReentrantLock lock = LOCAL_LOCK_MAP.computeIfAbsent(generateLockKey(getId(), key), k -> new ReentrantLock()); + String lockKey = generateLockKey(getId(), key); + Semaphore lock = LOCAL_LOCK_MAP.computeIfAbsent(lockKey, k -> new Semaphore(1)); + boolean flag = false; try { - boolean flag = lock.tryLock(5, TimeUnit.SECONDS); + flag = lock.tryAcquire(5, TimeUnit.SECONDS); + // 调用putObject()方法时会在LOCAL_LOCK_MAP删除锁,会出现一种场景,这里获得锁,但LOCAL_LOCK_MAP中已经删除了该锁,必须在这里释放锁 + if (flag) { + if (lock != LOCAL_LOCK_MAP.get(lockKey)) { + lock.release(); + } + } } catch (InterruptedException e) { // ignore } cachedElement = getCache().get(key); if (cachedElement != null) { - if (lock.isLocked() && lock.isHeldByCurrentThread()) { - lock.unlock(); + if (flag) { + if (lock == LOCAL_LOCK_MAP.get(lockKey)) { + LOCAL_LOCK_MAP.remove(lockKey); + } + lock.release(); } return cachedElement.getObjectValue(); } @@ -152,14 +166,18 @@ public class NeatLogicConcurrentSafeCache implements Cache { } /** + * 不管SQL语句执行是否抛异常,都会调用putObject方法 + * SQL语句执行成功得到结果为null时,value为[] + * SQL语句执行异常时,value为null * {@inheritDoc} */ @Override public void putObject(Object key, Object value) { getCache().put(new Element(key, value)); - ReentrantLock lock = LOCAL_LOCK_MAP.remove(generateLockKey(getId(), key)); - if (lock != null && lock.isLocked() && lock.isHeldByCurrentThread()) { - lock.unlock(); + String lockKey = generateLockKey(getId(), key); + Semaphore lock = LOCAL_LOCK_MAP.remove(lockKey); + if (lock != null) { + lock.release(); } } @@ -168,12 +186,13 @@ public class NeatLogicConcurrentSafeCache implements Cache { */ @Override public Object removeObject(Object key) { + String lockKey = generateLockKey(getId(), key); + Semaphore lock = LOCAL_LOCK_MAP.remove(lockKey); + if (lock != null) { + lock.release(); + } Object obj = getObject(key); getCache().remove(key); - ReentrantLock lock = LOCAL_LOCK_MAP.remove(generateLockKey(getId(), key)); - if (lock != null && lock.isLocked() && lock.isHeldByCurrentThread()) { - lock.unlock(); - } return obj; } @@ -223,54 +242,11 @@ public class NeatLogicConcurrentSafeCache implements Cache { return "EHCache {" + id + "}"; } - // DYNAMIC PROPERTIES - - /** - * Sets the time to idle for an element before it expires. Is only used if - * the element is not eternal. - * - * @param timeToIdleSeconds the default amount of time to live for an element from its - * last accessed or modified date - */ - public void setTimeToIdleSeconds(long timeToIdleSeconds) { - getCache().getCacheConfiguration().setTimeToIdleSeconds(timeToIdleSeconds); - } - - /** - * Sets the time to idle for an element before it expires. Is only used if - * the element is not eternal. - * - * @param timeToLiveSeconds the default amount of time to live for an element from its - * creation date - */ - public void setTimeToLiveSeconds(long timeToLiveSeconds) { - getCache().getCacheConfiguration().setTimeToLiveSeconds(timeToLiveSeconds); - } - - /** - * Sets the maximum objects to be held in memory (0 = no limit). - * evicted (0 == no limit) - */ - public void setMaxEntriesLocalHeap(long maxEntriesLocalHeap) { - getCache().getCacheConfiguration().setMaxEntriesLocalHeap(maxEntriesLocalHeap); - } - - /** - * Sets the maximum number elements on Disk. 0 means unlimited. - * unlimited. - */ - public void setMaxEntriesLocalDisk(long maxEntriesLocalDisk) { - getCache().getCacheConfiguration().setMaxEntriesLocalDisk(maxEntriesLocalDisk); - } - - /** - * Sets the eviction policy. An invalid argument will set it to null. - * - * @param memoryStoreEvictionPolicy a String representation of the policy. One of "LRU", "LFU" or - * "FIFO". - */ - public void setMemoryStoreEvictionPolicy(String memoryStoreEvictionPolicy) { - getCache().getCacheConfiguration().setMemoryStoreEvictionPolicy(memoryStoreEvictionPolicy); + public static List getAllLockKeyList() { + List resultList = new ArrayList<>(); + for (Map.Entry entry : LOCAL_LOCK_MAP.entrySet()) { + resultList.add(entry.getKey()); + } + return resultList; } - } -- Gitee