diff --git a/src/main/java/com/njcn/middle/cache/constant/CacheConstant.java b/src/main/java/com/njcn/middle/cache/constant/CacheConstant.java new file mode 100644 index 0000000..944dd89 --- /dev/null +++ b/src/main/java/com/njcn/middle/cache/constant/CacheConstant.java @@ -0,0 +1,19 @@ +package com.njcn.middle.cache.constant; + +/** + * Redis 缓存相关常量。 + */ +public final class CacheConstant { + + private CacheConstant() { + } + + /** + * 空值标记:回源结果为 null 时写入此值(穿透防护)。 + * 内含 NUL 控制字符(Java unicode 转义书写),fastjson 序列化任何对象都不会产出含 NUL 的裸文本,故无冲突。 + */ + public static final String NULL_SENTINEL = "\u0000NULL\u0000"; + + /** 击穿互斥锁 key 后缀(由数据 key 派生)。 */ + public static final String LOCK_SUFFIX = ":__lock__"; +} diff --git a/src/main/java/com/njcn/middle/cache/support/CacheKeyBuilder.java b/src/main/java/com/njcn/middle/cache/support/CacheKeyBuilder.java new file mode 100644 index 0000000..a562ce3 --- /dev/null +++ b/src/main/java/com/njcn/middle/cache/support/CacheKeyBuilder.java @@ -0,0 +1,36 @@ +package com.njcn.middle.cache.support; + +import cn.hutool.core.util.StrUtil; +import com.njcn.middle.cache.constant.CacheConstant; + +/** + * 缓存 key 构造器:统一前缀 +(可选)环境隔离段。 + * + *

基础:{@code keyPrefix + bizKey};开启隔离且 env 非空:{@code keyPrefix + env + ":" + bizKey}。 + * 锁 key 由数据 key 派生,保证数据与其锁落在同一隔离域。 + */ +public class CacheKeyBuilder { + + private final String keyPrefix; + private final boolean envIsolation; + private final String env; + + public CacheKeyBuilder(String keyPrefix, boolean envIsolation, String env) { + this.keyPrefix = keyPrefix == null ? "" : keyPrefix; + this.envIsolation = envIsolation; + this.env = env; + } + + /** 业务 key → 实际数据 key。 */ + public String build(String bizKey) { + if (envIsolation && StrUtil.isNotBlank(env)) { + return keyPrefix + env + ":" + bizKey; + } + return keyPrefix + bizKey; + } + + /** 数据 key 派生锁 key。 */ + public String buildLock(String bizKey) { + return build(bizKey) + CacheConstant.LOCK_SUFFIX; + } +} diff --git a/src/test/java/com/njcn/middle/cache/support/CacheKeyBuilderTest.java b/src/test/java/com/njcn/middle/cache/support/CacheKeyBuilderTest.java new file mode 100644 index 0000000..32503cc --- /dev/null +++ b/src/test/java/com/njcn/middle/cache/support/CacheKeyBuilderTest.java @@ -0,0 +1,34 @@ +package com.njcn.middle.cache.support; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +class CacheKeyBuilderTest { + + @Test + void buildWithPrefixOnly() { + CacheKeyBuilder kb = new CacheKeyBuilder("cache:", false, ""); + assertEquals("cache:user:1", kb.build("user:1")); + } + + @Test + void buildWithEnvIsolation() { + CacheKeyBuilder kb = new CacheKeyBuilder("cache:", true, "prod"); + assertEquals("cache:prod:user:1", kb.build("user:1")); + } + + @Test + void envIsolationButBlankEnvFallsBack() { + CacheKeyBuilder kb = new CacheKeyBuilder("cache:", true, ""); + assertEquals("cache:user:1", kb.build("user:1")); + } + + @Test + void buildLockDerivesFromDataKey() { + assertEquals("cache:user:1:__lock__", + new CacheKeyBuilder("cache:", false, "").buildLock("user:1")); + assertEquals("cache:prod:user:1:__lock__", + new CacheKeyBuilder("cache:", true, "prod").buildLock("user:1")); + } +}