Spring Data Redis で Null サポートキャッシュ
Spring なプロジェクトで Spring Date Redis
を使うと、Redis へのキャッシュが簡単にできるようになります。
ただ、キャッシュの難しい点の1つとして、null なものをキャッシュするかどうかという話があります。
時間を掛けて取得を試みたものが null だった場合(無かった場合)、null であったことを記憶しておきたいか、という話です。
今までは Spring Date Redis
を使っていると、null はキャッシュ対象外でした。
(もちろん、シリアライザー/デシリアライザーをカスタマイズすることで対応はできます)
これは今まで結構困っていたのですが、バージョン 1.8 から公式にサポートされるようになっていました。
Support caching null values via RedisCache
https://jira.spring.io/browse/DATAREDIS-553
使い方としては、RedisCacheManager
のコンストラクタ引数に null をサポートするかのフラグをセットするだけです。
以下、サンプルです。
@EnableCaching
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
@Autowired
private JedisConnectionFactory jedisConnectionFactory;
@Bean
public RedisTemplate<Object, Object> redisTemplate() {
RedisTemplate<Object, Object> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(jedisConnectionFactory);
redisTemplate.setKeySerializer(new GenericJackson2JsonRedisSerializer(""));
redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer(""));
return redisTemplate;
}
@Bean
public CacheManager cacheManager() {
List<String> cacheNames = Arrays.asList("person");
RedisCacheManager redisCacheManager = new RedisCacheManager(redisTemplate(), cacheNames, true); // 最後に引数で Null をキャッシュするようにする。
// キャッシュキーのプレフィックスの設定
redisCacheManager.setUsePrefix(true);
redisCacheManager.setCachePrefix(new RedisCachePrefix() {
@Override
public byte[] prefix(String cacheName) {
return ("SAMPLE:" + cacheName + ":").getBytes(StandardCharsets.UTF_8);
}
});
return redisCacheManager;
}
}
@Data
@AllArgsConstructor
public class Person {
private int id;
private String name;
}
@Slf4j
@Service
public class PersonService {
@Cacheable("person")
public Person findById(int id) {
log.info("called findById. id = {}", id);
try {
TimeUnit.SECONDS.sleep(id);
} catch (InterruptedException e) {
// ignore
}
return id >= 10 ? null : new Person(id, "ほげ太郎" + id);
}
}
@Slf4j
@RunWith(SpringRunner.class)
@SpringBootTest
public class PersonServiceTest {
@Autowired
PersonService target;
@Autowired
CacheManager cacheManager;
@Before
public void setup() {
Cache cache = cacheManager.getCache("person");
cache.clear();
}
@Test
public void testFindByIdNull() {
StopWatch stopWatch = new StopWatch();
stopWatch.start();
Person p1 = target.findById(10); // 10s かかる
stopWatch.stop();
log.info("result = {}, elapsed = {}", p1, stopWatch.getLastTaskTimeMillis());
assertNull(p1);
assertTrue(stopWatch.getLastTaskTimeMillis() > 10000);
stopWatch.start();
Person p2 = target.findById(10); // 2回目はキャッシュが効いて速い
stopWatch.stop();
log.info("result = {}, elapsed = {}", p2, stopWatch.getLastTaskTimeMillis());
assertNull(p2);
assertTrue(stopWatch.getLastTaskTimeMillis() < 1000);
}
}
2017-06-23 12:01:34.434 INFO 3246 --- [ main] n.s.cachesample.service.PersonService : called findById. id = 10
2017-06-23 12:01:44.449 INFO 3246 --- [ main] n.s.c.service.PersonServiceTest : result = null, elapsed = 10058
2017-06-23 12:01:44.498 INFO 3246 --- [ main] n.s.c.service.PersonServiceTest : result = null, elapsed = 49
ちなみに Redis にどう保存されているかというと以下のようになっています。
$ redis-cli -h 192.168.99.100 get 'SAMPLE:hello:10' 12:06:23
"{\"@class\":\"org.springframework.cache.support.NullValue\"}"
これは、GenericJackson2JsonRedisSerializer で定義されてる以下のクラスによるものです。
/**
* {@link StdSerializer} adding class information required by default typing. This allows de-/serialization of
* {@link NullValue}.
*
* @author Christoph Strobl
* @since 1.8
*/
private class NullValueSerializer extends StdSerializer<NullValue> {
private static final long serialVersionUID = 1999052150548658808L;
private final String classIdentifier;
/**
* @param classIdentifier can be {@literal null} and will be defaulted to {@code @class}.
*/
NullValueSerializer(String classIdentifier) {
super(NullValue.class);
this.classIdentifier = StringUtils.hasText(classIdentifier) ? classIdentifier : "@class";
}
/*
* (non-Javadoc)
* @see com.fasterxml.jackson.databind.ser.std.StdSerializer#serialize(java.lang.Object, com.fasterxml.jackson.core.JsonGenerator, com.fasterxml.jackson.databind.SerializerProvider)
*/
@Override
public void serialize(NullValue value, JsonGenerator jgen, SerializerProvider provider)
throws IOException {
jgen.writeStartObject();
jgen.writeStringField(classIdentifier, NullValue.class.getName());
jgen.writeEndObject();
}
}
Author And Source
この問題について(Spring Data Redis で Null サポートキャッシュ), 我々は、より多くの情報をここで見つけました https://qiita.com/sinsengumi/items/9d4c7ef83a0225617659著者帰属:元の著者の情報は、元のURLに含まれています。著作権は原作者に属する。
Content is automatically searched and collected through network algorithms . If there is a violation . Please contact us . We will adjust (correct author information ,or delete content ) as soon as possible .