前端视角 Java Web 入门手册 5.6:真实世界 Web 开发——Redis

Redis 简介

Redis(Remote Dictionary Server)是一个开源的 NoSQL 数据库,数据存储在内存中以实现高速读写,同时支持持久化到磁盘,可以用作数据库、缓存和消息代理。

主要特性

  • 内存优先:数据存储在内存中,读写速度极快(读约 10 万次 / 秒,写约 8 万次 / 秒)。
  • 持久化支持:通过 RDB 快照和 AOF 日志实现数据持久化,保障数据安全。
  • 多数据结构:支持字符串(String)、哈希(Hash)、列表(List)、集合(Set)、有序集合(Sorted Set)、位图(Bitmap)、HyperLogLog 等,满足不同场景需求。
  • 原子操作:所有操作都是原子性的,确保数据一致性。
  • 分布式架构:支持主从复制、哨兵(Sentinel)、集群(Cluster)模式,提升可用性和扩展性。
  • 丰富功能:发布 / 订阅、Lua 脚本、事务、管道(Pipeline)、LRU 淘汰策略等。

在 Spring Boot 中使用 Redis

环境准备

首先需要本地安装 redis,Mac 用户可以使用 homebrew 安装,安装完成后启动服务

bash 复制代码
redis-server

添加依赖

在 Spring Boot 项目中添加 redis 依赖

xml 复制代码
<!-- Spring Data Redis -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

配置 Redis

java 复制代码
# Redis服务器地址
spring.redis.host=localhost

# Redis服务器端口
spring.redis.port=6379

# Redis连接超时(毫秒)
spring.redis.timeout=60000

# 设置密码
# spring.redis.password=yourpassword

# Spring缓存配置
spring.cache.type=redis

启用缓存

在 Spring Boot 应用的主类或配置类上添加@EnableCaching注解,启用缓存功能。

java 复制代码
@SpringBootApplication
@EnableCaching // 启用缓存
public class RedisDemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(RedisDemoApplication.class, args);
    }
}

构建实体类

  • @RedisHash("User"):指示这个实体类在 Redis 中存储时的键前缀为 "User"
  • @Id:标识该字段为主键
java 复制代码
package com.example.rediscrud.model;

import org.springframework.data.annotation.Id;
import org.springframework.data.redis.core.RedisHash;

import java.io.Serializable;

@RedisHash("User")
public class User implements Serializable {
    @Id
    private String id;
    private String name;

    // 无参构造器
    public User() {}

    // 全参构造器
    public User(String id, String name) {
        this.id = id;
        this.name = name;
    }

    // Getters 和 Setters
    public String getId() {
        return id;
    }

    public String getName() {
        return name;
    }
  
    public void setId(String id) {
        this.id = id;
    }

    public void setName(String name){
        this.name=name;
    }
}

Redis 并没有 namespace 的概念,所有 key 在相同层级存储,一般通过 key 的前缀来区分

创建 Repository 接口

可以直接使用 Redis API 来操作缓存内容

java 复制代码
@Repository
public class UserRepository {
    private static final String KEY_PREFIX = "user:";

    @Autowired
    private RedisTemplate<String, User> redisTemplate;

    // 创建用户
    public void save(User user) {
        String key = KEY_PREFIX + user.getId();
        redisTemplate.opsForValue().set(key, user);
    }

    // 根据 ID 获取用户
    public User findById(String id) {
        String key = KEY_PREFIX + id;
        return redisTemplate.opsForValue().get(key);
    }

    // 更新用户信息
    public void update(User user) {
        String key = KEY_PREFIX + user.getId();
        redisTemplate.opsForValue().set(key, user);
    }

    // 根据 ID 删除用户
    public void delete(String id) {
        String key = KEY_PREFIX + id;
        redisTemplate.delete(key);
    }
}    

但 Spring Data Redis 提供了 RedisRepository(继承自 CrudRepository)接口,允许我们方便地进行 CRUD 操作。

java 复制代码
package com.example.rediscrud.repository;

import com.example.rediscrud.model.User;
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface UserRepository extends CrudRepository<User, String> {
    // 继承了CrudRepository,已经包含了常用的CRUD方法
}

创建 Service 类

创建一个 UserService 类,封装业务逻辑,利用 UserRepository 进行数据操作,并可以添加缓存逻辑

  • @CachePut: 更新缓存。每次调用该方法都会将返回值更新到缓存中。
  • @Cacheable: 先从缓存中获取数据,如果不存在则调用方法并将结果存入缓存。
  • @CacheEvict: 从缓存中移除数据。
java 复制代码
@Service
public class UserService {

    @Autowired
    private UserRepository userRepository;

    /**
     * 创建/更新用户
     *
     * @param user 用户对象
     * @return 保存后的用户对象
     */
    @CachePut(value = "users", key = "#user.id")
    public User saveUser(User user) {
        return userRepository.save(user);
    }

    /**
     * 根据ID获取用户信息
     *
     * @param id 用户ID
     * @return Optional<User>
     */
    @Cacheable(value = "users", key = "#id")
    public Optional<User> getUserById(String id) {
        return userRepository.findById(id);
    }

    /**
     * 获取所有用户
     *
     * @return Iterable<User>
     */
    public Iterable<User> getAllUsers() {
        return userRepository.findAll();
    }

    /**
     * 根据ID删除用户
     *
     * @param id 用户ID
     */
    @CacheEvict(value = "users", key = "#id")
    public void deleteUserById(String id) {
        userRepository.deleteById(id);
    }
}

序列化

默认情况下,Spring Boot 使用 JDK 序列化 来存储缓存数据。这可能导致 Redis 中存储的数据不可读,且性能较低。为了提高效率和可读性,可以创建 RedisConfig 类配置Redis使用 Jackson 进行JSON 序列化。

  • @Configuration:标识一个类为 Spring 配置类,允许定义多个@Bean方法,生成 Spring 容器管理的 bean。
  • @Bean:标识一个方法,表示该方法将返回一个需要由 Spring 容器管理的 bean
java 复制代码
@Configuration
public class RedisConfig {
    
    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory connectionFactory) {
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(connectionFactory);
        
        // 使用Jackson2JsonRedisSerializer来序列化和反序列化redis的value值
        Jackson2JsonRedisSerializer<Object> serializer = new Jackson2JsonRedisSerializer<>(Object.class);
        
        ObjectMapper objectMapper = new ObjectMapper();
        // 允许访问所有属性
        objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        // 启用默认Typing。Deprecated from Jackson 2.10, use `activateDefaultTyping` with appropriate settings
        objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        serializer.setObjectMapper(objectMapper);
        
        // 设置key和value的序列化方式
        template.setKeySerializer(new StringRedisSerializer());
        template.setValueSerializer(serializer);
        template.setHashKeySerializer(new StringRedisSerializer());
        template.setHashValueSerializer(serializer);
        
        template.afterPropertiesSet();
        return template;
    }
}
相关推荐
假女吖☌5 分钟前
Maven 处理依赖冲突
java·python·maven
eguid_19 分钟前
WebRTC工作原理详细介绍、WebRTC信令交互过程和WebRTC流媒体传输协议介绍
java·音视频·webrtc·实时音视频
元亓亓亓22 分钟前
Java后端开发day41--IO流(一)--FileOutputStream&FileInputStream
java·开发语言
gxn_mmf22 分钟前
典籍知识问答模块AI问答功能feedbackBug修改+添加对话名称修改功能
前端·后端·bug
·云扬·30 分钟前
【PmHub后端篇】PmHub整合TransmittableThreadLocal (TTL)缓存用户数据
java·开发语言·缓存
向哆哆1 小时前
Spring Boot快速开发:从零开始搭建一个企业级应用
java·spring boot·后端
gs801402 小时前
检查当前 Docker 使用的 默认运行时(default runtime)方法
java·开发语言·eureka
hello_ejb32 小时前
聊聊Spring AI autoconfigure模块的拆分
java·人工智能·spring
小马爱打代码2 小时前
Spring Boot + MyBatis-Plus 高并发读写分离实战
spring boot·mybatis
wolfengi2 小时前
Idea Code Templates配置
java·ide·intellij-idea