Spring boot使用redis进行缓存,key有\xac\xed\x00\x05t\x00\x06

问题描述 投票:0回答:5

我想使用Spring缓存@Cacheable来管理缓存。 而真正的缓存是redis。

我的代码是这样的:

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

在我收到帖子请求后

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

redis服务器出现奇怪的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 缓存

奇怪的-redis-key-with-spring-data-jedis

如何像StringRedisTemplate一样设置@Cacheable的Serializer默认:

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

我的应用程序属性:

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

构建.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")
}
java spring caching redis
5个回答
13
投票

创建redis模板

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;
}

为什么它会创建一个奇怪的字符串作为键?

密钥是根据方法中存在的参数属性创建的,该方法被注释为可缓存。这就是spring从redis读取缓存值的方式。


4
投票

Spring 的缓存特性允许使用不同的缓存实现。其中之一是 Redis。它可以与

RedisCacheManager
类一起使用。 Spring 文档 说:

如果 Redis 可用且已配置,则

RedisCacheManager
会自动配置。

这是我建议影响 Redis - 缓存 - 集成的方法:

  1. 自行将

    RedisCacheManager
    定义为 bean。

  2. RedisTemplate
    传递给
    RedisCacheManager
    的构造函数。

我在互联网上找到了一个使用编程配置的示例。还有一个使用基于 XML 的配置的示例


3
投票

就像mm759的回答:

  1. 自行将RedisCacheManager定义为bean。

    1. 将RedisTemplate传递给RedisCacheManager的构造函数。

这段代码将解决我的问题:

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;
    }

}

Redis 存储如下:

enter image description here


3
投票

这是我的两分钱。 🪙🏛️

TL;博士
假设您正在寻找一种解决方案来删除所有这些奇怪的键。不要浪费时间编写一行 bash 解决方案。这是行不通的,

redis-cli KEYS "user*" | xargs redis-cli DEL
(来源:如何删除钥匙?)。您的密钥采用二进制格式,通过管道传输它们不会产生预期的结果。扩展创建密钥的脚本的功能以删除它们(例如 Python、Java、Go 等)。或者,如果可以的话,删除所有密钥
redis-cli flushall
(来源:如何使用 Redis 以原子方式删除与模式匹配的密钥

就将密钥作为二进制数据而言,我不确定有什么好处(重复,二进制密钥,而不是数据)。因为,至少根据这些帖子,它的空间效率和时间效率可能低于预期,存储纯文本数据占用的空间比存储更少-等效的混乱是二进制存储方法比基于文本的方法更有效。当然,如果您故意转换了密钥。

如果您希望密钥采用字符串格式,请在 Redis 模板上将密钥序列化器设置为

StringRedisSerializer
,如 @Rohith K 的答案中所指出的。这将使您能够使用上面引用的模式匹配命令删除键。

redisTemplate.setKeySerializer(new StringRedisSerializer());

最后,这里有一些关于这些有趣的符号

"\xac\xed\x00\x05t\x00:"
如何添加到 Redis 键之前的更多讨论:

  1. Java创建带有奇怪字符的Redis键和内容
  2. Spring Boot Redis 将 POJO 列表存储为值
  3. Spring Redis删除不删除key

我希望这篇文章能为您节省一些时间。快乐编码🔥


0
投票

8年后,我在Spring项目中使用Redission遇到了同样的问题。

在 redis 中设置值后,如下所示:

RMap<String, String> map = redissonClient.getMap("hash-key");
map.put(field, value);

字段和值都将以“>”为前缀。我用谷歌搜索但未能找到任何可用的解决方案。我查看了源代码,发现了一个奇怪的方法

    /**
     * Returns map instance by name
     * using provided codec for both map keys and values.
     *
     * @param <K> type of key
     * @param <V> type of value
     * @param name - name of object
     * @param codec - codec for keys and values
     * @return Map object
     */
    <K, V> RMap<K, V> getMap(String name, Codec codec);

因此我将代码更改为

RMap<String, String> map = redissonClient.getMap(CODE_ICON_URLS_KEY, StringCodec.INSTANCE);

砰,成功了。

© www.soinside.com 2019 - 2024. All rights reserved.