feat(cache): 缓存常量与 key 构造器(前缀 + 环境隔离 + 锁 key 派生)
This commit is contained in:
19
src/main/java/com/njcn/middle/cache/constant/CacheConstant.java
vendored
Normal file
19
src/main/java/com/njcn/middle/cache/constant/CacheConstant.java
vendored
Normal file
@@ -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__";
|
||||||
|
}
|
||||||
36
src/main/java/com/njcn/middle/cache/support/CacheKeyBuilder.java
vendored
Normal file
36
src/main/java/com/njcn/middle/cache/support/CacheKeyBuilder.java
vendored
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
package com.njcn.middle.cache.support;
|
||||||
|
|
||||||
|
import cn.hutool.core.util.StrUtil;
|
||||||
|
import com.njcn.middle.cache.constant.CacheConstant;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 缓存 key 构造器:统一前缀 +(可选)环境隔离段。
|
||||||
|
*
|
||||||
|
* <p>基础:{@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;
|
||||||
|
}
|
||||||
|
}
|
||||||
34
src/test/java/com/njcn/middle/cache/support/CacheKeyBuilderTest.java
vendored
Normal file
34
src/test/java/com/njcn/middle/cache/support/CacheKeyBuilderTest.java
vendored
Normal file
@@ -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"));
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user