diff --git a/src/main/java/com/njcn/middle/cache/template/RedisCacheEnhanceTemplate.java b/src/main/java/com/njcn/middle/cache/template/RedisCacheEnhanceTemplate.java index 2e6347d..b6f42fa 100644 --- a/src/main/java/com/njcn/middle/cache/template/RedisCacheEnhanceTemplate.java +++ b/src/main/java/com/njcn/middle/cache/template/RedisCacheEnhanceTemplate.java @@ -90,7 +90,9 @@ public class RedisCacheEnhanceTemplate { } public boolean exists(String key) { - return Boolean.TRUE.equals(redis.hasKey(keyBuilder.build(key))); + // 与 get 口径一致:空值标记不算"存在"(物理 hasKey 会把空标记算存在,与 get→null 打架) + String raw = redis.opsForValue().get(keyBuilder.build(key)); + return raw != null && !codec.isNullSentinel(raw); } // ---- 续期 ---- diff --git a/src/test/java/com/njcn/middle/cache/template/RedisCacheEnhanceTemplateTest.java b/src/test/java/com/njcn/middle/cache/template/RedisCacheEnhanceTemplateTest.java index 311f59d..6f4ab8c 100644 --- a/src/test/java/com/njcn/middle/cache/template/RedisCacheEnhanceTemplateTest.java +++ b/src/test/java/com/njcn/middle/cache/template/RedisCacheEnhanceTemplateTest.java @@ -23,6 +23,7 @@ import java.util.function.Consumer; import java.util.function.Supplier; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTimeoutPreemptively; @@ -318,4 +319,24 @@ class RedisCacheEnhanceTemplateTest { void constructorAcceptsDefaults() { new RedisCacheEnhanceTemplate(redis, keyBuilder, codec, new RedisCacheProperties()); } + + // ---- #7: exists 排除空值标记(与 get 口径一致) ---- + + @Test + void existsTrueForRealValue() { + when(valueOps.get("cache:user:1")).thenReturn(JSON.toJSONString(new User(1L, "a"))); + assertTrue(template.exists("user:1")); + } + + @Test + void existsFalseForNullSentinel() { + when(valueOps.get("cache:user:1")).thenReturn(CacheConstant.NULL_SENTINEL); + assertFalse(template.exists("user:1")); + } + + @Test + void existsFalseForMissing() { + when(valueOps.get("cache:user:1")).thenReturn(null); + assertFalse(template.exists("user:1")); + } }