Java Redis字符串案例怎么操作

wen java案例 30

Java操作Redis字符串:从入门到实战的完整案例解析

目录导读

  1. Redis字符串基础与Java集成环境搭建
  2. Java操作Redis字符串的5个核心方法
  3. 实战案例:缓存用户会话信息
  4. 常见踩坑与优化策略
  5. 问答环节:高频疑难解答

Java Redis字符串案例怎么操作

Redis字符串基础与Java集成环境搭建

1 Redis字符串的本质

Redis的字符串(String)是最基础的数据类型,但功能远不止存储文本,它可以存储普通字符串、JSON序列化数据、数字(支持原子加减)、二进制数据(如图片Base64编码)等,其最大存储容量为512MB,是构建缓存、计数器、分布式锁的核心工具。

2 Java连接Redis的3种主流方式

  • Jedis:轻量级客户端,API直接对应Redis命令,适合小规模项目
  • Lettuce:基于Netty的异步客户端,支持连接池和集群模式,Spring Boot默认集成
  • Redisson:提供分布式对象和锁的高级封装,学习曲线稍陡

环境配置示例(以Lettuce + Spring Boot为例)

<!-- pom.xml -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-pool2</artifactId>
</dependency>
# application.yml
spring:
  redis:
    host: localhost
    port: 6379
    password: your_password
    lettuce:
      pool:
        max-active: 8
        max-idle: 8
        min-idle: 0

Java操作Redis字符串的5个核心方法

1 基础存取(SET/GET)

@Autowired
private StringRedisTemplate stringRedisTemplate;
public void basicExample() {
    // 存储字符串
    stringRedisTemplate.opsForValue().set("user:name", "张三");
    // 读取字符串
    String name = stringRedisTemplate.opsForValue().get("user:name");
    System.out.println(name); // 输出:张三
    // 带过期时间的存储(单位:秒)
    stringRedisTemplate.opsForValue().set("tmp:code", "123456", 60);
}

注意StringRedisTemplateRedisTemplate<String, String>区别在于前者已设置序列化器为String方式,后者需自行配置。

2 批量操作(MSET/MGET)

public void batchExample() {
    Map<String, String> userMap = new HashMap<>();
    userMap.put("user:1:name", "李四");
    userMap.put("user:1:age", "25");
    userMap.put("user:1:city", "北京");
    // 批量写入
    stringRedisTemplate.opsForValue().multiSet(userMap);
    // 批量读取
    List<String> keys = Arrays.asList("user:1:name", "user:1:age");
    List<String> values = stringRedisTemplate.opsForValue().multiGet(keys);
    // values = [李四, 25]
}

3 数字操作(INCR/DECR)

public void numericExample() {
    String key = "counter:pageviews";
    // 原子自增(返回自增后的值)
    Long visitCount = stringRedisTemplate.opsForValue().increment(key);
    // 自增指定步长
    stringRedisTemplate.opsForValue().increment(key, 10);
    // 自减
    stringRedisTemplate.opsForValue().decrement(key);
    // 注意:如果key不存在,初始值为0再操作
}

应用场景:文章阅读量、商品秒杀库存、接口调用次数统计。

4 字符串长度与追加(STRLEN/APPEND)

public void stringManipulation() {
    stringRedisTemplate.opsForValue().set("msg", "Hello");
    // 获取字符串长度
    Long length = stringRedisTemplate.opsForValue().size("msg"); // 5
    // 追加字符串(返回追加后总长度)
    Integer newLength = stringRedisTemplate.opsForValue().append("msg", " World");
    // msg变为"Hello World"
}

5 设置值并返回旧值(GETSET)

public String getSetExample() {
    String oldValue = stringRedisTemplate.opsForValue().getAndSet("user:token", "new_token_abc");
    // 第一次调用返回null(如果key不存在),第二次返回旧token
    return oldValue;
}

典型用途:定时刷新token时保留上一个值用于校验。


实战案例:缓存用户会话信息

1 需求描述

用户登录后,将用户的基本信息(userId、昵称、角色、权限)缓存到Redis,设置过期时间为30分钟,并在每次请求中校验会话有效性。

2 代码实现

@Component
public class SessionManager {
    @Autowired
    private StringRedisTemplate redisTemplate;
    private static final String SESSION_PREFIX = "session:";
    private static final long EXPIRE_SECONDS = 1800;
    // 缓存会话
    public void cacheSession(String token, UserSession session) {
        String json = JSONObject.toJSONString(session);
        redisTemplate.opsForValue().set(SESSION_PREFIX + token, json, EXPIRE_SECONDS, TimeUnit.SECONDS);
    }
    // 获取会话(自动延期)
    public UserSession getSession(String token) {
        String key = SESSION_PREFIX + token;
        String json = redisTemplate.opsForValue().get(key);
        if (json == null) {
            return null;
        }
        // 每次访问重置过期时间(滑动窗口)
        redisTemplate.expire(key, EXPIRE_SECONDS, TimeUnit.SECONDS);
        return JSONObject.parseObject(json, UserSession.class);
    }
    // 删除会话(登出)
    public void removeSession(String token) {
        redisTemplate.delete(SESSION_PREFIX + token);
    }
}

3 性能优化建议

  • 连接池配置max-active根据并发量设置,通常为CPU核心数的2倍
  • 序列化选择:使用Jackson或FastJSON时,@JsonFormat注解避免日期序列化问题
  • 批量处理:当需要同时存储多个会话时,使用multiSet替代循环set

常见踩坑与优化策略

1 踩坑1:序列化混乱导致的数据乱码

现象:用RedisTemplate存储中文,控制台看到\xac\xed\x00\x05t\x00\x04乱码。
原因:默认使用JdkSerializationRedisSerializer,存储时带了类结构信息。
解决:配置自定义序列化器:

@Bean
public RedisTemplate<String, String> redisTemplate(RedisConnectionFactory factory) {
    RedisTemplate<String, String> template = new RedisTemplate<>();
    template.setConnectionFactory(factory);
    template.setKeySerializer(new StringRedisSerializer());
    template.setValueSerializer(new StringRedisSerializer());
    return template;
}

2 踩坑2:大Key引发的性能问题

风险:单个字符串超过10MB时,GET命令可能导致Redis阻塞其他操作。
优化方案

  • 使用RedisBloom布隆过滤器预检数据是否存在
  • 将大JSON拆分为多个小key,例如user:100:base_infouser:100:ext_info
  • 启用Redis的--bigkeys参数定期扫描

3 踩坑3:字段命名不规范导致查找困难

最佳实践

  • 使用冒号分层:业务:对象:属性,如order:202310:status
  • 避免无意义的key前缀,如a123这种
  • 设置合理的TTL,防止内存泄漏

问答环节:高频疑难解答

Q1:StringRedisTemplate和RedisTemplate有什么区别?
A:StringRedisTemplate继承自RedisTemplate,但默认使用String序列化器,因此只支持字符串类型的key和value,RedisTemplate默认使用JDK序列化,可存储对象,但需要自行配置序列化器,日常缓存字符串推荐直接使用StringRedisTemplate。

Q2:Redis字符串如何实现分布式锁?
A:利用SET key value NX EX seconds命令的原子性。

Boolean locked = stringRedisTemplate.opsForValue()
    .setIfAbsent("lock:order", "1");
if (locked) {
    try {
        // 执行业务
    } finally {
        stringRedisTemplate.delete("lock:order");
    }
}

注意:生产环境建议使用Redisson,避免锁释放异常。

Q3:为什么我存JSON到Redis,取出来解析时报错?
A:常见原因有3个:

  1. 序列化时使用了Jackson@JsonFormat,但未在Redis中设置时区
  2. 存储的JSON字符串末尾包含不可见字符(如换行符)
  3. 使用了不同客户端(如Jedis和Lettuce)序列化方式不一致
    排查:先打印原字符串查看完整内容,再手动用在线JSON工具校验。

Q4:如何批量删除以某个前缀开头的key?
A:Redis原生不支持通配符删除,需组合使用SCANDEL

public void deleteByPrefix(String prefix) {
    Set<String> keys = new HashSet<>();
    ScanOptions options = ScanOptions.scanOptions().match(prefix + "*").count(1000).build();
    Cursor<String> cursor = redisTemplate.scan(options);
    while (cursor.hasNext()) {
        keys.add(cursor.next());
    }
    if (!keys.isEmpty()) {
        redisTemplate.delete(keys);
    }
}

Q5:Redis字符串最大能存多大?超过怎么办?
A:官方限制512MB,如果数据超过,建议方案:

  • 分片存储:user_data_1, user_data_2
  • 使用Hash类型替代(适合结构化数据)
  • 二级缓存(Redis+本地缓存)

通过以上案例和技巧,您已经掌握了Java操作Redis字符串的核心技能,建议在实际项目中先将简单的缓存需求用字符串类型实现,再逐步探索Hash、List等更复杂的数据结构。合理的key命名和TTL设计是Redis性能优化的第一步

抱歉,评论功能暂时关闭!