Мне нужно реализовать кэширование запрошенных данных (с моим собственным TTL - см. Переменную expirationTimeInSeconds
; по этой причине я не использую абстракцию @Cacheable из Spring
) в Redis
, используя Spring
RedisTemplate
.
Итак, я не хочу делать чрезмерные звонки (computer.compute (..) в фрагменте ниже), если данные уже есть. Проблема в том, что у меня есть несколько экземпляров в центре обработки данных, а не в одной JVM. Следовательно, параллелизм Java здесь не поможет, только на одном уровне JVM
.
Таким образом, в моем решении ниже я всегда получаю пустые данные (пустую карту, см. "// Always True = (" комментарий) между открытием и закрытием Redis transaction
, т.е. после operations.multi()
, но между operations.exec()
.
String multiKey = compoundKey(channelId + "." + sourceId);
try {
redisTemplate.execute(new SessionCallback<HashOperations<String, Object, Object>>() {
@Override
public HashOperations<String, Object, Object> execute(RedisOperations operations) throws DataAccessException {
operations.multi();
HashOperations<String, Object, Object> hashOperations = operations.opsForHash();
Map<Object, Object> values = hashOperations.entries(multiKey);
// Always True =(
if (CollectionUtils.isEmpty(values)) {
dataHolder.setValue(computer.apply(channelId, sourceId));
if (dataHolder.getValue() != null) {
MyData data = dataHolder.getValue();
Map<String, String> data = new HashMap<>();
data.put(CHANNEL_NAME_KEY, data.getChannelName());
data.put(CHANNEL_LABEL_KEY, data.getChannelLabel());
data.put(SOURCE_NAME_KEY, data.getSourceName());
hashOperations.putAll(multiKey, data);
operations.expire(multiKey, expirationTimeInSeconds, TimeUnit.SECONDS);
}
} else {
dataHolder.setValue(new MyData(values.get(CHANNEL_NAME_KEY).toString(),
values.get(CHANNEL_LABEL_KEY).toString(), values.get(SOURCE_NAME_KEY).toString()));
}
operations.exec();
return null;
}
});
} catch (Exception e) {
log.error("Error while obtaining MyData backed by Redis for channelId {}, sourceId {}: {}",
channelId, sourceId, e.getMessage(), e);
}
Почему это так? Может кто-нибудь объяснить, что я делаю неправильно, и что может быть возможным здесь исправить?