fix(cache): exists 排除空值标记,与 get 口径一致

exists 原用 hasKey,会把持有空值标记的 key 判为"存在"(true),而 get 对同一 key
返回 null,二者口径打架。改为读值判断:空标记/缺失均返回 false,真实值返回 true。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
root
2026-06-26 10:00:06 +08:00
parent 8b90fe099e
commit c40f153642
2 changed files with 24 additions and 1 deletions

View File

@@ -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);
}
// ---- 续期 ----

View File

@@ -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"));
}
}