当前位置: 首页 > news >正文

SpringBoot3.x入门到精通系列:2.6 整合 Redis 详解

SpringBoot 3.x 整合 Redis 详解

🎯 Redis简介

Redis是一个开源的内存数据结构存储系统,可以用作数据库、缓存和消息代理。它支持多种数据结构,如字符串、哈希、列表、集合、有序集合等。

核心特性

  • 高性能: 基于内存存储,读写速度极快
  • 数据结构丰富: 支持多种数据类型
  • 持久化: 支持RDB和AOF两种持久化方式
  • 高可用: 支持主从复制、哨兵模式、集群模式
  • 原子操作: 所有操作都是原子性的

🚀 快速开始

1. 添加依赖

<dependencies><!-- SpringBoot Starter Web --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!-- SpringBoot Redis Starter --><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><!-- JSON处理 --><dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-databind</artifactId></dependency><!-- 缓存注解支持 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-cache</artifactId></dependency>
</dependencies>

2. Redis配置

spring:# Redis配置data:redis:# Redis服务器地址host: localhost# Redis服务器端口port: 6379# Redis密码(如果有的话)password: # 数据库索引(默认为0)database: 0# 连接超时时间timeout: 2000ms# Lettuce连接池配置lettuce:pool:# 连接池最大连接数max-active: 8# 连接池最大空闲连接数max-idle: 8# 连接池最小空闲连接数min-idle: 0# 连接池最大阻塞等待时间max-wait: -1ms# 空闲连接验证查询超时时间time-between-eviction-runs: 60s# 缓存配置cache:type: redisredis:# 缓存过期时间time-to-live: 600000# 是否缓存空值cache-null-values: false# 键前缀key-prefix: "cache:"# 是否使用键前缀use-key-prefix: true# 日志配置
logging:level:org.springframework.data.redis: DEBUG

🔧 Redis配置类

1. RedisTemplate配置

package com.example.demo.config;import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;@Configuration
public class RedisConfig {/*** RedisTemplate配置*/@Beanpublic RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory connectionFactory) {RedisTemplate<String, Object> template = new RedisTemplate<>();template.setConnectionFactory(connectionFactory);// JSON序列化配置Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class);ObjectMapper objectMapper = new ObjectMapper();objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);objectMapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL);jackson2JsonRedisSerializer.setObjectMapper(objectMapper);// String序列化配置StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();// key采用String的序列化方式template.setKeySerializer(stringRedisSerializer);// hash的key也采用String的序列化方式template.setHashKeySerializer(stringRedisSerializer);// value序列化方式采用jacksontemplate.setValueSerializer(jackson2JsonRedisSerializer);// hash的value序列化方式采用jacksontemplate.setHashValueSerializer(jackson2JsonRedisSerializer);template.afterPropertiesSet();return template;}/*** StringRedisTemplate配置(用于简单的字符串操作)*/@Beanpublic StringRedisTemplate stringRedisTemplate(RedisConnectionFactory connectionFactory) {StringRedisTemplate template = new StringRedisTemplate();template.setConnectionFactory(connectionFactory);return template;}
}

2. 缓存配置

package com.example.demo.config;import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializationContext;
import org.springframework.data.redis.serializer.StringRedisSerializer;import java.time.Duration;
import java.util.HashMap;
import java.util.Map;@Configuration
@EnableCaching
public class CacheConfig {@Beanpublic CacheManager cacheManager(RedisConnectionFactory connectionFactory) {// 默认缓存配置RedisCacheConfiguration defaultConfig = RedisCacheConfiguration.defaultCacheConfig().entryTtl(Duration.ofMinutes(10)) // 默认过期时间10分钟.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer())).serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer())).disableCachingNullValues(); // 不缓存null值// 不同缓存的个性化配置Map<String, RedisCacheConfiguration> cacheConfigurations = new HashMap<>();// 用户缓存:30分钟过期cacheConfigurations.put("users", defaultConfig.entryTtl(Duration.ofMinutes(30)));// 产品缓存:1小时过期cacheConfigurations.put("products", defaultConfig.entryTtl(Duration.ofHours(1)));// 系统配置缓存:24小时过期cacheConfigurations.put("configs", defaultConfig.entryTtl(Duration.ofHours(24)));return RedisCacheManager.builder(connectionFactory).cacheDefaults(defaultConfig).withInitialCacheConfigurations(cacheConfigurations).build();}
}

📊 Redis工具类

package com.example.demo.util;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;@Component
public class RedisUtil {@Autowiredprivate RedisTemplate<String, Object> redisTemplate;@Autowiredprivate StringRedisTemplate stringRedisTemplate;// =============================Common============================/*** 指定缓存失效时间*/public boolean expire(String key, long time) {try {if (time > 0) {redisTemplate.expire(key, time, TimeUnit.SECONDS);}return true;} catch (Exception e) {e.printStackTrace();return false;}}/*** 根据key获取过期时间*/public long getExpire(String key) {return redisTemplate.getExpire(key, TimeUnit.SECONDS);}/*** 判断key是否存在*/public boolean hasKey(String key) {try {return redisTemplate.hasKey(key);} catch (Exception e) {e.printStackTrace();return false;}}/*** 删除缓存*/public void del(String... key) {if (key != null && key.length > 0) {if (key.length == 1) {redisTemplate.delete(key[0]);} else {redisTemplate.delete((Collection<String>) List.of(key));}}}// ============================String=============================/*** 普通缓存获取*/public Object get(String key) {return key == null ? null : redisTemplate.opsForValue().get(key);}/*** 普通缓存放入*/public boolean set(String key, Object value) {try {redisTemplate.opsForValue().set(key, value);return true;} catch (Exception e) {e.printStackTrace();return false;}}/*** 普通缓存放入并设置时间*/public boolean set(String key, Object value, long time) {try {if (time > 0) {redisTemplate.opsForValue().set(key, value, time, TimeUnit.SECONDS);} else {set(key, value);}return true;} catch (Exception e) {e.printStackTrace();return false;}}/*** 递增*/public long incr(String key, long delta) {if (delta < 0) {throw new RuntimeException("递增因子必须大于0");}return redisTemplate.opsForValue().increment(key, delta);}/*** 递减*/public long decr(String key, long delta) {if (delta < 0) {throw new RuntimeException("递减因子必须大于0");}return redisTemplate.opsForValue().increment(key, -delta);}// ================================Hash=================================/*** HashGet*/public Object hget(String key, String item) {return redisTemplate.opsForHash().get(key, item);}/*** 获取hashKey对应的所有键值*/public Map<Object, Object> hmget(String key) {return redisTemplate.opsForHash().entries(key);}/*** HashSet*/public boolean hmset(String key, Map<String, Object> map) {try {redisTemplate.opsForHash().putAll(key, map);return true;} catch (Exception e) {e.printStackTrace();return false;}}/*** HashSet 并设置时间*/public boolean hmset(String key, Map<String, Object> map, long time) {try {redisTemplate.opsForHash().putAll(key, map);if (time > 0) {expire(key, time);}return true;} catch (Exception e) {e.printStackTrace();return false;}}/*** 向一张hash表中放入数据,如果不存在将创建*/public boolean hset(String key, String item, Object value) {try {redisTemplate.opsForHash().put(key, item, value);return true;} catch (Exception e) {e.printStackTrace();return false;}}/*** 删除hash表中的值*/public void hdel(String key, Object... item) {redisTemplate.opsForHash().delete(key, item);}// ============================Set=============================/*** 根据key获取Set中的所有值*/public Set<Object> sGet(String key) {try {return redisTemplate.opsForSet().members(key);} catch (Exception e) {e.printStackTrace();return null;}}/*** 将数据放入set缓存*/public long sSet(String key, Object... values) {try {return redisTemplate.opsForSet().add(key, values);} catch (Exception e) {e.printStackTrace();return 0;}}/*** 获取set缓存的长度*/public long sGetSetSize(String key) {try {return redisTemplate.opsForSet().size(key);} catch (Exception e) {e.printStackTrace();return 0;}}/*** 移除值为value的*/public long setRemove(String key, Object... values) {try {Long count = redisTemplate.opsForSet().remove(key, values);return count;} catch (Exception e) {e.printStackTrace();return 0;}}// ===============================List=================================/*** 获取list缓存的内容*/public List<Object> lGet(String key, long start, long end) {try {return redisTemplate.opsForList().range(key, start, end);} catch (Exception e) {e.printStackTrace();return null;}}/*** 获取list缓存的长度*/public long lGetListSize(String key) {try {return redisTemplate.opsForList().size(key);} catch (Exception e) {e.printStackTrace();return 0;}}/*** 通过索引 获取list中的值*/public Object lGetIndex(String key, long index) {try {return redisTemplate.opsForList().index(key, index);} catch (Exception e) {e.printStackTrace();return null;}}/*** 将list放入缓存*/public boolean lSet(String key, Object value) {try {redisTemplate.opsForList().rightPush(key, value);return true;} catch (Exception e) {e.printStackTrace();return false;}}/*** 将list放入缓存*/public boolean lSet(String key, List<Object> value) {try {redisTemplate.opsForList().rightPushAll(key, value);return true;} catch (Exception e) {e.printStackTrace();return false;}}
}

🏗️ 实体类和Service

1. 用户实体类

package com.example.demo.entity;import java.io.Serializable;
import java.time.LocalDateTime;public class User implements Serializable {private static final long serialVersionUID = 1L;private Long id;private String username;private String email;private Integer age;private String phone;private LocalDateTime createTime;// 构造函数public User() {}public User(Long id, String username, String email, Integer age) {this.id = id;this.username = username;this.email = email;this.age = age;}// Getter和Setter方法public Long getId() { return id; }public void setId(Long id) { this.id = id; }public String getUsername() { return username; }public void setUsername(String username) { this.username = username; }public String getEmail() { return email; }public void setEmail(String email) { this.email = email; }public Integer getAge() { return age; }public void setAge(Integer age) { this.age = age; }public String getPhone() { return phone; }public void setPhone(String phone) { this.phone = phone; }public LocalDateTime getCreateTime() { return createTime; }public void setCreateTime(LocalDateTime createTime) { this.createTime = createTime; }@Overridepublic String toString() {return "User{" +"id=" + id +", username='" + username + '\'' +", email='" + email + '\'' +", age=" + age +", phone='" + phone + '\'' +", createTime=" + createTime +'}';}
}

2. 用户Service(使用缓存注解)

package com.example.demo.service;import com.example.demo.entity.User;
import com.example.demo.util.RedisUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicLong;@Service
public class UserService {@Autowiredprivate RedisUtil redisUtil;// 模拟数据库private final ConcurrentHashMap<Long, User> userDatabase = new ConcurrentHashMap<>();private final AtomicLong idGenerator = new AtomicLong(1);// 初始化一些测试数据public UserService() {userDatabase.put(1L, new User(1L, "张三", "zhangsan@example.com", 25));userDatabase.put(2L, new User(2L, "李四", "lisi@example.com", 30));userDatabase.put(3L, new User(3L, "王五", "wangwu@example.com", 28));idGenerator.set(4);}/*** 查询所有用户(缓存)*/@Cacheable(value = "users", key = "'all'")public List<User> findAll() {System.out.println("从数据库查询所有用户...");// 模拟数据库查询延迟try {Thread.sleep(1000);} catch (InterruptedException e) {Thread.currentThread().interrupt();}return new ArrayList<>(userDatabase.values());}/*** 根据ID查询用户(缓存)*/@Cacheable(value = "users", key = "#id")public User findById(Long id) {System.out.println("从数据库查询用户: " + id);// 模拟数据库查询延迟try {Thread.sleep(500);} catch (InterruptedException e) {Thread.currentThread().interrupt();}return userDatabase.get(id);}/*** 创建用户(更新缓存)*/@CachePut(value = "users", key = "#result.id")@CacheEvict(value = "users", key = "'all'") // 清除所有用户的缓存public User createUser(User user) {Long id = idGenerator.getAndIncrement();user.setId(id);user.setCreateTime(LocalDateTime.now());userDatabase.put(id, user);System.out.println("创建用户: " + user);return user;}/*** 更新用户(更新缓存)*/@CachePut(value = "users", key = "#user.id")@CacheEvict(value = "users", key = "'all'") // 清除所有用户的缓存public User updateUser(User user) {User existingUser = userDatabase.get(user.getId());if (existingUser != null) {existingUser.setUsername(user.getUsername());existingUser.setEmail(user.getEmail());existingUser.setAge(user.getAge());existingUser.setPhone(user.getPhone());System.out.println("更新用户: " + existingUser);return existingUser;}throw new RuntimeException("用户不存在: " + user.getId());}/*** 删除用户(清除缓存)*/@CacheEvict(value = "users", key = "#id")@CacheEvict(value = "users", key = "'all'") // 清除所有用户的缓存public boolean deleteUser(Long id) {User removedUser = userDatabase.remove(id);if (removedUser != null) {System.out.println("删除用户: " + removedUser);return true;}return false;}/*** 使用RedisUtil进行缓存操作*/public void cacheUserWithUtil(User user) {String key = "user:util:" + user.getId();redisUtil.set(key, user, 300); // 缓存5分钟System.out.println("使用RedisUtil缓存用户: " + key);}/*** 从RedisUtil获取缓存的用户*/public User getCachedUserWithUtil(Long id) {String key = "user:util:" + id;Object cachedUser = redisUtil.get(key);if (cachedUser instanceof User) {System.out.println("从RedisUtil获取缓存用户: " + key);return (User) cachedUser;}return null;}
}

🎮 Controller层

package com.example.demo.controller;import com.example.demo.entity.User;
import com.example.demo.service.UserService;
import com.example.demo.util.RedisUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;import java.util.HashMap;
import java.util.List;
import java.util.Map;@RestController
@RequestMapping("/api/redis")
@CrossOrigin(origins = "*")
public class RedisController {@Autowiredprivate UserService userService;@Autowiredprivate RedisUtil redisUtil;/*** 获取所有用户(带缓存)*/@GetMapping("/users")public ResponseEntity<List<User>> getAllUsers() {List<User> users = userService.findAll();return ResponseEntity.ok(users);}/*** 根据ID获取用户(带缓存)*/@GetMapping("/users/{id}")public ResponseEntity<User> getUserById(@PathVariable Long id) {User user = userService.findById(id);if (user != null) {return ResponseEntity.ok(user);}return ResponseEntity.notFound().build();}/*** 创建用户*/@PostMapping("/users")public ResponseEntity<User> createUser(@RequestBody User user) {User createdUser = userService.createUser(user);return ResponseEntity.ok(createdUser);}/*** 更新用户*/@PutMapping("/users/{id}")public ResponseEntity<User> updateUser(@PathVariable Long id, @RequestBody User user) {user.setId(id);User updatedUser = userService.updateUser(user);return ResponseEntity.ok(updatedUser);}/*** 删除用户*/@DeleteMapping("/users/{id}")public ResponseEntity<Void> deleteUser(@PathVariable Long id) {boolean deleted = userService.deleteUser(id);if (deleted) {return ResponseEntity.noContent().build();}return ResponseEntity.notFound().build();}/*** Redis基本操作测试*/@PostMapping("/test")public ResponseEntity<Map<String, Object>> testRedis() {Map<String, Object> result = new HashMap<>();// 字符串操作redisUtil.set("test:string", "Hello Redis", 60);String stringValue = (String) redisUtil.get("test:string");result.put("string", stringValue);// 数字操作redisUtil.set("test:counter", 0);long counter = redisUtil.incr("test:counter", 1);result.put("counter", counter);// Hash操作Map<String, Object> hashMap = new HashMap<>();hashMap.put("name", "Redis测试");hashMap.put("version", "7.0");redisUtil.hmset("test:hash", hashMap, 60);Map<Object, Object> hashValue = redisUtil.hmget("test:hash");result.put("hash", hashValue);// Set操作redisUtil.sSet("test:set", "value1", "value2", "value3");result.put("set", redisUtil.sGet("test:set"));// List操作redisUtil.lSet("test:list", "item1");redisUtil.lSet("test:list", "item2");redisUtil.lSet("test:list", "item3");result.put("list", redisUtil.lGet("test:list", 0, -1));return ResponseEntity.ok(result);}/*** 使用RedisUtil缓存用户*/@PostMapping("/users/{id}/cache")public ResponseEntity<String> cacheUser(@PathVariable Long id) {User user = userService.findById(id);if (user != null) {userService.cacheUserWithUtil(user);return ResponseEntity.ok("用户已缓存");}return ResponseEntity.notFound().build();}/*** 从RedisUtil获取缓存的用户*/@GetMapping("/users/{id}/cached")public ResponseEntity<User> getCachedUser(@PathVariable Long id) {User cachedUser = userService.getCachedUserWithUtil(id);if (cachedUser != null) {return ResponseEntity.ok(cachedUser);}return ResponseEntity.notFound().build();}
}

📊 最佳实践

1. 缓存策略

  • Cache-Aside: 应用程序直接管理缓存
  • Write-Through: 写入时同时更新缓存和数据库
  • Write-Behind: 异步写入数据库
  • Refresh-Ahead: 主动刷新即将过期的缓存

2. 性能优化

  • 合理设置过期时间
  • 使用连接池
  • 批量操作
  • 避免大key

3. 安全考虑

  • 设置密码认证
  • 网络安全配置
  • 数据加密
  • 访问控制

本文关键词: Redis, 缓存, 内存数据库, SpringBoot整合, 数据结构, 性能优化

http://www.lryc.cn/news/608663.html

相关文章:

  • Python 基础语法(一):从常量到运算符
  • jvm之jconsole的使用
  • MySQL连接算法和小表驱动大表的原理
  • 初识prometheus
  • Selenium Web 自动化
  • 【软考中级网络工程师】知识点之 RIP 协议
  • 华为智能家居与Spring人工智能
  • 决策树学习全解析:从理论到实战
  • C++手撕基于ID3算法的决策树
  • 著作权登记遇难题:创作者如何突破确权困境?
  • 自动驾驶中的传感器技术19——Camera(10)
  • ELECTRICAL靶场
  • ClickHouse Windows迁移方案与测试
  • 【动态规划算法】路径问题
  • WebRTC前处理模块技术详解:音频3A处理与视频优化实践
  • Node.js (Express) + MySQL + Redis构建项目流程
  • 决策树的实际案例
  • sqli-labs:Less-25关卡详细解析
  • 50天50个小项目 (Vue3 + Tailwindcss V4) ✨ | TodoList(代办事项组件)
  • 子区间问题
  • 主机序列号的修改方法与原理
  • Azure DevOps 中的代理
  • 渗透作业4
  • LeetCode - 合并两个有序链表 / 删除链表的倒数第 N 个结点
  • webrtc弱网-QualityScaler 源码分析与算法原理
  • PLC传感器接线与输出信号接线
  • WSUS服务器数据库维护与性能优化技术白皮书
  • 力扣 hot100 Day64
  • 六、Linux核心服务与包管理
  • 若没有安全可靠性保障,对于工程应用而言,AI或许就是大玩具吗?