[JAVA] Null-Support-Cache in Spring Data Redis

Die Verwendung von "Spring Date Redis" in einem Spring-Projekt erleichtert das Zwischenspeichern in Redis.

Eine der Schwierigkeiten beim Zwischenspeichern ist jedoch, ob ** Null-Dinge ** zwischengespeichert werden sollen. Wenn derjenige, den Sie im Laufe der Zeit versucht haben, null war (wenn nicht), möchten Sie sich daran erinnern, dass er null war.

Bisher wurde bei Verwendung von "Spring Date Redis" null nicht zwischengespeichert. (Natürlich kann dies durch Anpassen des Serializers / Deserializers behoben werden.) Dies war bisher ein Problem, wurde jedoch seit Version 1.8 offiziell unterstützt.

Support caching null values via RedisCache https://jira.spring.io/browse/DATAREDIS-553

Alles, was Sie tun müssen, ist das Konstruktorargument "RedisCacheManager" so zu setzen, dass es für die Nullunterstützung markiert wird. Unten ist ein Beispiel.

Application.java


@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); //Schließlich Cache Null als Argument.

        //Festlegen des Cache-Schlüsselpräfix
        redisCacheManager.setUsePrefix(true);
        redisCacheManager.setCachePrefix(new RedisCachePrefix() {
            @Override
            public byte[] prefix(String cacheName) {
                return ("SAMPLE:" + cacheName + ":").getBytes(StandardCharsets.UTF_8);
            }
        });

        return redisCacheManager;
    }
}

Person.java


@Data
@AllArgsConstructor
public class Person {
    private int id;
    private String name;
}

PersonService.java


@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, "Hogetaro" + id);
    }
}

PersonServiceTest.java


@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); //Dauert 10s
        stopWatch.stop();
        log.info("result = {}, elapsed = {}", p1, stopWatch.getLastTaskTimeMillis());
        assertNull(p1);
        assertTrue(stopWatch.getLastTaskTimeMillis() > 10000);

        stopWatch.start();
        Person p2 = target.findById(10); //Das zweite Mal funktioniert der Cache und ist schnell
        stopWatch.stop();
        log.info("result = {}, elapsed = {}", p2, stopWatch.getLastTaskTimeMillis());
        assertNull(p2);
        assertTrue(stopWatch.getLastTaskTimeMillis() < 1000);
    }
}

TestResults


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

Übrigens, wie es in Redis gespeichert wird, ist wie folgt.

$ redis-cli -h 192.168.99.100 get 'SAMPLE:hello:10'                                                                                                                                                                                12:06:23
"{\"@class\":\"org.springframework.cache.support.NullValue\"}"

Dies liegt an den folgenden Klassen, die in GenericJackson2JsonRedisSerializer definiert sind.

NullValueSerializer


/**
 * {@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();
    }
}

https://github.com/spring-projects/spring-data-redis/blob/master/src/main/java/org/springframework/data/redis/serializer/GenericJackson2JsonRedisSerializer.java

Recommended Posts

Null-Support-Cache in Spring Data Redis
Existiert mit der Spezifikation in Spring Data JPA
Antwortdaten direkt im Frühjahr schreiben
Informationen zum Festlegen des Gültigkeitszeitraums beim Speichern des Caches in Redis mit Spring Cache
Machen Sie die where-Klauselvariable in Spring Data JPA
Spring Boot (1 Serie) + spring-security-oauth2 + Redis Session + Heroku mit SerializationException
Injizieren Sie den Logger im Frühjahr
Mehrsprachige Unterstützung für Spring Framework
Verwenden Sie Interceptor im Frühjahr
Spring Data JDBC-Vorschau
Microservices in Spring Cloud
Holen Sie sich Cookies im Frühling
Federdaten Dynamodb-Falle
Erstellen Sie eine API zum Senden und Empfangen von Json-Daten mit Spring