Spring boot caching with redis,key have \xac\xed\x00\x05t\x00\x06
Asked Answered
K

4

13

I want to use Spring cache @Cacheable to manager cache. And the real cache is redis.

my code like that:

@PostMapping("/post")
@CachePut(value = "abc", key = "#key")
public String putInRedis(@RequestParam String key, @RequestParam String value) {
    saveInDB(key, value);

    return value;
}

@GetMapping("/get")
@Cacheable(value = "abc", key = "#key")
public String queryRedis(@RequestParam String key) {

    return findByKey(key);
}

After I have the post request which is

localhost:8080/post?key=key&value=value

the redis server appear a weird key

127.0.0.1:6379> keys *
1) "abc:\xac\xed\x00\x05t\x00\x03key"
127.0.0.1:6379> GET "abc:\xac\xed\x00\x05t\x00\x03key"
"\xac\xed\x00\x05t\x00\x05value"

Spring caching

weird-redis-key-with-spring-data-jedis

how to set @Cacheable's Serializer like StringRedisTemplate default:

public StringRedisTemplate() {
    RedisSerializer<String> stringSerializer = new StringRedisSerializer();
    setKeySerializer(stringSerializer);
    setValueSerializer(stringSerializer);
    setHashKeySerializer(stringSerializer);
    setHashValueSerializer(stringSerializer);
}

my application.properties:

spring.redis.host=localhost
spring.redis.password=
spring.redis.port=6379

build.gradle

group 'io.freezhan'
version '1.0-SNAPSHOT'

buildscript {
    repositories {
        maven {
            url 'https://plugins.gradle.org/m2/'
        }
    }
    dependencies {
        classpath 'org.springframework.boot:spring-boot-gradle-plugin:1.4.0.RELEASE'
    }
}

task wrapper(type: Wrapper) {
    gradleVersion = '2.13'
    distributionUrl = "https://services.gradle.org/distributions/gradle-$gradleVersion-all.zip"
}

apply plugin: 'java'
apply plugin: 'spring-boot'

sourceCompatibility = 1.5

repositories {
    mavenCentral()
}

dependencies {
    compile("org.springframework.boot:spring-boot-starter-web") {
        exclude module: "spring-boot-starter-tomcat"
    }
    compile("org.springframework.boot:spring-boot-starter-data-redis")
    compile("org.springframework.boot:spring-boot-starter-jetty")
    compile("org.springframework.boot:spring-boot-starter-actuator")
    compile 'org.projectlombok:lombok:1.16.10'
    testCompile("junit:junit")
}
Kanara answered 5/9, 2016 at 6:5 Comment(2)
How does your configuration of caching with Redis look like?Girlhood
my application.properties is spring.redis.host=localhost spring.redis.password= spring.redis.port=6379Sandoval
G
4

The caching - feature of Spring allows to use different cache - implementations. One of them is Redis. It can be used with the class RedisCacheManager. The Spring documentation says:

If Redis is available and configured, the RedisCacheManager is auto-configured.

This is the approach that I propose to influence the Redis - caching - integration:

  1. Define the RedisCacheManager as bean on your own.

  2. Pass the RedisTemplate to the constructor of RedisCacheManager.

I found an example for this on the Internet using a programmmatic configuration. There is also an example using XML-based configuration.

Girlhood answered 5/9, 2016 at 6:35 Comment(3)
Is there any way implement this in application.properties or yaml file. Don't use to write code~Sandoval
I hardly know both, but I think it's not possible. I couldn't find annotations on RedisCacheManager that allow it.Girlhood
Passing RedisTemplate to the constructor of RedisCacheManager is deprecated now. Any new way to stop the weird key generation?Pronoun
N
13

Create a redis template

private RedisTemplate<String, ?> createRedisTemplateForEntity() {
        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<String, Object>();
        redisTemplate.setConnectionFactory(getRedisConnectionFactory());
        redisTemplate.setHashValueSerializer(new StringRedisSerializer());
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        redisTemplate.setValueSerializer(new StringRedisSerializer());
        redisTemplate.setHashKeySerializer(new StringRedisSerializer());
        redisTemplate.afterPropertiesSet();

    return redisTemplate;
}

Why is it creating a weird string as key?

The key is created based on the argument attributes present in your method which is annotated as cacheable. This is how spring reads the cache value from redis.

Neuburger answered 5/9, 2016 at 6:36 Comment(1)
The default RedisTemplate will not appear weird key, because the serializer is StringRedisSerializer. But the default @Cacheable(value = "abc", key = "#key") maybe use defaultSerializer = new JdkSerializationRedisSerializer(); Define own cacheManager and set this redisTemplate will solve my problem. thanks for your answerSandoval
G
4

The caching - feature of Spring allows to use different cache - implementations. One of them is Redis. It can be used with the class RedisCacheManager. The Spring documentation says:

If Redis is available and configured, the RedisCacheManager is auto-configured.

This is the approach that I propose to influence the Redis - caching - integration:

  1. Define the RedisCacheManager as bean on your own.

  2. Pass the RedisTemplate to the constructor of RedisCacheManager.

I found an example for this on the Internet using a programmmatic configuration. There is also an example using XML-based configuration.

Girlhood answered 5/9, 2016 at 6:35 Comment(3)
Is there any way implement this in application.properties or yaml file. Don't use to write code~Sandoval
I hardly know both, but I think it's not possible. I couldn't find annotations on RedisCacheManager that allow it.Girlhood
Passing RedisTemplate to the constructor of RedisCacheManager is deprecated now. Any new way to stop the weird key generation?Pronoun
K
3

like mm759's answer:

  1. Define the RedisCacheManager as bean on your own.

    1. Pass the RedisTemplate to the constructor of RedisCacheManager.

this code will solve my problem:

package io;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.CacheManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.serializer.StringRedisSerializer;

/**
 * Created by freezhan on 16/9/5.
 */
@Configuration
public class CacheConfig {

    @Autowired
    private StringRedisTemplate redisTemplate;

    @Bean
    public CacheManager cacheManager() {
        RedisCacheManager cacheManager = new RedisCacheManager(redisTemplate);
        return cacheManager;
    }

}

and the redis store like this:

enter image description here

Kanara answered 5/9, 2016 at 7:13 Comment(1)
its deprecated..now RedisCacheManager not allowing StringRedisTemplate to be in parameterPremiership
L
3

Here are my two cents. 🪙🏛️

TL;DR
Suppose you are looking for a solution to delete all those weird keys. Don't waste time composing a one-line bash solution. This won't work, redis-cli KEYS "user*" | xargs redis-cli DEL (source: How do I remove keys?). Your keys are in binary format piping them won't produce the expected results. Extend the functionality of the script that created the keys to delete them as well (Think Python, Java, Go, etc.). Alternatively, delete all keys if you can afford it redis-cli flushall (source: How to atomically delete keys matching a pattern using Redis

In terms of having your keys as binary data, I am unsure what the benefits are (repeating, binary keys, not data). Since, it might turn out that it's less space-efficient and time-efficient than expected, at least according to these posts, does-storing-plain-text-data-take-up-less-space-than-storing-the-equivalent-mess, are-binary-storage-methods-more-efficient-than-text-based-ones. Of course, if you have converted your keys on purpose.

If you wish to have your keys in string format, on the Redis template, set the key serializer as a StringRedisSerializer, as pointed out in the answer by @Rohith K. This would enable you to delete keys by using the pattern matching command quoted above.

redisTemplate.setKeySerializer(new StringRedisSerializer());

Finally, here are some more discussions about how those funny symbols, "\xac\xed\x00\x05t\x00:", got prepended to your Redis keys:

  1. Java creating Redis key and content with strange characters
  2. Spring Boot Redis store a list of POJOs as values
  3. Spring Redis Delete does not delete key

I hope this post saves you some time. Happy coding 🔥

Larimer answered 6/1, 2022 at 11:41 Comment(1)
Excellent anwer! This should be the accepted one.Declassify

© 2022 - 2024 — McMap. All rights reserved.