Java整合Redis缓存的完整案例
项目环境准备
Maven依赖配置
<dependencies>
<!-- Spring Boot Starter -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Redis -->
<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>
</dependencies>
配置文件
application.yml
spring:
redis:
host: localhost
port: 6379
password: # 如果有密码则填写
database: 0
timeout: 5000ms
lettuce:
pool:
max-active: 8
max-idle: 8
min-idle: 0
max-wait: -1ms
Redis配置类
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 {
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory connectionFactory) {
RedisTemplate<String, Object> template = new RedisTemplate<>();
template.setConnectionFactory(connectionFactory);
// JSON序列化配置
Jackson2JsonRedisSerializer<Object> jacksonSerializer = new Jackson2JsonRedisSerializer<>(Object.class);
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
om.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL);
jacksonSerializer.setObjectMapper(om);
// String序列化配置
StringRedisSerializer stringSerializer = new StringRedisSerializer();
// key使用String序列化
template.setKeySerializer(stringSerializer);
template.setHashKeySerializer(stringSerializer);
// value使用JSON序列化
template.setValueSerializer(jacksonSerializer);
template.setHashValueSerializer(jacksonSerializer);
template.afterPropertiesSet();
return template;
}
}
业务实体类
import java.io.Serializable;
import java.util.Date;
public class User implements Serializable {
private static final long serialVersionUID = 1L;
private Long id;
private String username;
private String email;
private Date createTime;
// getters and setters
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 Date getCreateTime() {
return createTime;
}
public void setCreateTime(Date createTime) {
this.createTime = createTime;
}
}
缓存工具类
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import java.util.concurrent.TimeUnit;
@Component
public class RedisCacheUtil {
@Autowired
private RedisTemplate<String, Object> redisTemplate;
/**
* 设置缓存
*/
public void set(String key, Object value) {
redisTemplate.opsForValue().set(key, value);
}
/**
* 设置缓存并指定过期时间
*/
public void set(String key, Object value, long timeout, TimeUnit unit) {
redisTemplate.opsForValue().set(key, value, timeout, unit);
}
/**
* 获取缓存
*/
public Object get(String key) {
return redisTemplate.opsForValue().get(key);
}
/**
* 删除缓存
*/
public boolean delete(String key) {
return Boolean.TRUE.equals(redisTemplate.delete(key));
}
/**
* 判断key是否存在
*/
public boolean exists(String key) {
return Boolean.TRUE.equals(redisTemplate.hasKey(key));
}
/**
* 设置过期时间
*/
public boolean expire(String key, long timeout, TimeUnit unit) {
return Boolean.TRUE.equals(redisTemplate.expire(key, timeout, unit));
}
/**
* 获取过期时间
*/
public long getExpire(String key, TimeUnit unit) {
Long expire = redisTemplate.getExpire(key, unit);
return expire != null ? expire : 0;
}
}
服务层实现
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.concurrent.TimeUnit;
@Service
public class UserService {
@Autowired
private RedisCacheUtil redisCacheUtil;
// 模拟数据库查询
public User getUserFromDB(Long userId) {
// 实际项目中这里应该是数据库查询
User user = new User();
user.setId(userId);
user.setUsername("user_" + userId);
user.setEmail("user" + userId + "@example.com");
user.setCreateTime(new Date());
// 模拟耗时操作
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return user;
}
/**
* 获取用户信息(带缓存)
* @param userId 用户ID
* @return 用户信息
*/
public User getUserWithCache(Long userId) {
String key = "user:" + userId;
// 1. 从缓存获取
User user = (User) redisCacheUtil.get(key);
if (user != null) {
System.out.println("从缓存获取用户信息: " + userId);
return user;
}
// 2. 缓存不存在,从数据库查询
System.out.println("从数据库获取用户信息: " + userId);
user = getUserFromDB(userId);
// 3. 存入缓存(设置过期时间1小时)
redisCacheUtil.set(key, user, 1, TimeUnit.HOURS);
return user;
}
/**
* 更新用户信息(更新缓存)
*/
public User updateUser(User user) {
// 1. 更新数据库
// 实际项目中这里是数据库更新操作
System.out.println("更新数据库用户信息: " + user.getId());
// 2. 更新缓存
String key = "user:" + user.getId();
redisCacheUtil.set(key, user, 1, TimeUnit.HOURS);
return user;
}
/**
* 删除用户(删除缓存)
*/
public void deleteUser(Long userId) {
// 1. 删除数据库记录
System.out.println("删除数据库用户: " + userId);
// 2. 删除缓存
String key = "user:" + userId;
redisCacheUtil.delete(key);
}
}
控制器层
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/api/users")
public class UserController {
@Autowired
private UserService userService;
@GetMapping("/{id}")
public User getUser(@PathVariable Long id) {
return userService.getUserWithCache(id);
}
@PutMapping
public User updateUser(@RequestBody User user) {
return userService.updateUser(user);
}
@DeleteMapping("/{id}")
public String deleteUser(@PathVariable Long id) {
userService.deleteUser(id);
return "用户删除成功";
}
}
使用注解方式(更推荐)
开启缓存注解
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Configuration;
@Configuration
@EnableCaching
public class CacheConfig {
}
使用@Cacheable注解
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
@Service
public class UserServiceAnnotated {
// 缓存用户信息
@Cacheable(value = "users", key = "#userId")
public User getUser(Long userId) {
// 数据库查询
return getUserFromDB(userId);
}
// 更新缓存
@CachePut(value = "users", key = "#user.id")
public User updateUser(User user) {
// 更新数据库
return user;
}
// 删除缓存
@CacheEvict(value = "users", key = "#userId")
public void deleteUser(Long userId) {
// 删除数据库记录
}
}
测试验证
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
public class RedisCacheTest {
@Autowired
private UserService userService;
@Test
public void testCache() {
Long userId = 1L;
// 第一次查询(从数据库)
System.out.println("第一次查询:");
long startTime = System.currentTimeMillis();
User user1 = userService.getUserWithCache(userId);
System.out.println("耗时:" + (System.currentTimeMillis() - startTime) + "ms");
// 第二次查询(从缓存)
System.out.println("第二次查询:");
startTime = System.currentTimeMillis();
User user2 = userService.getUserWithCache(userId);
System.out.println("耗时:" + (System.currentTimeMillis() - startTime) + "ms");
// 验证数据一致性
System.out.println("用户信息一致:" + user1.getUsername().equals(user2.getUsername()));
}
}
最佳实践建议
- 合理设置过期时间:根据业务需求设置合适的TTL
- 缓存穿透防护:对不存在的数据也缓存空值或使用布隆过滤器
- 缓存雪崩防护:过期时间添加随机值,避免大批量同时失效
- 热点数据预热:系统启动时预加载热点数据到缓存
- 监控告警:监控缓存命中率、内存使用等指标
这个完整的案例展示了如何在Spring Boot中整合Redis缓存,提供了基础使用方式和实际开发中的最佳实践。
