Redis在项目中常见的用法
Redis是一个开源高性能的键值对数据库,它以其内存中数据存储,键过期策略,持久化,事务,丰富的数据类型支持以及原子操作等特性,在项目中扮演着关键的角色。以下是一些简易的spring boot项目。
1、缓存
Redis可以作为应用程序的缓冲层,减少数据库的读取压力,提高访问速度。
使用场景描述
假设我们有一个在线书店,用户可以查看书籍的详细信息。每次用户请求书籍详情时,后端需要查询数据库以获取书籍信息。为了提高性能,我们可以使用Redis缓存来存储热门书籍的信息,以减少对数据库的查询次数。
环境准备
-
按照Java环境
-
按照redis,确保其运行成功
-
创建一个spring boot项目,并导入以下依赖
-
spring-boot-starter-data-redis
-
jackson-databind
-
jedis
-
slf4j-log4j12
-
lombok
-
spring-boot-starter-web
-
1、所需POM依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<!-- ✅ 加上 Spring Boot 父项目 -->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.18</version>
<relativePath/>
</parent>
<groupId>org.example</groupId>
<artifactId>Store</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<!-- Spring Boot Starter Data 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>
<version>2.11.1</version>
</dependency>
<!-- Spring Boot Starter Test(可选) -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.13.4.2</version>
</dependency>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.6.0</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.6.4</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
</project>
2、实体类Book.java
package org.example.Entity;
import lombok.Data;
import java.io.Serializable;
import java.math.BigDecimal;
@Data
public class Book implements Serializable {
private static final long serialVersionUID = 1L;
private String id ;
private String title;
private String author;
private String isbn;
private BigDecimal price;
private String description;
private String category;
}
3、模拟数据库访问层BookRepository
package org.example.BookRepository;
import org.example.Entity.Book;
import org.springframework.stereotype.Repository;
import javax.annotation.PostConstruct;
import java.util.HashMap;
import java.util.Map;
@Repository
public class BookRepository {
//模拟数据库,用map存储
private Map<String , Book> bookDatabase = new HashMap<>();
@PostConstruct
public void init(){
Book book1 = new Book();
book1.setId("1");
book1.setTitle("深入理解Java虚拟机");
book1.setAuthor("周志明");
book1.setIsbn("978-7-111-12345-6");
book1.setPrice(new java.math.BigDecimal("89.00"));
book1.setDescription("Java开发者必读的JVM经典书籍");
book1.setCategory("编程");
Book book2 = new Book();
book2.setId("2");
book2.setTitle("Spring Boot 实战");
book2.setAuthor("Craig Walls");
book2.setIsbn("978-7-111-54321-0");
book2.setPrice(new java.math.BigDecimal("79.00"));
book2.setDescription("Spring Boot 官方推荐学习书籍");
book2.setCategory("编程");
bookDatabase.put(book1.getId(),book1);
bookDatabase.put(book2.getId(),book2);
}
//根据id查询数据,模拟数据库
public Book findById(String id ){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
return bookDatabase.get(id);
}
public Book save(Book book){
bookDatabase.put(book.getId(), book);
return book;
}
public void delete(String id){
bookDatabase.remove(id);
}
}
4、Redis配置文件RedisConfig
package org.example.Config;
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.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
/**
* Redis 配置类
* 配置 RedisTemplate 的序列化方式,让 Key 存为字符串,Value 存为 JSON
*/
@Configuration
public class RedisConfig {
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
RedisTemplate<String, Object> template = new RedisTemplate<>();
template.setConnectionFactory(factory);
// 1. Key 使用 String 序列化(方便在 Redis 客户端查看)
template.setKeySerializer(new StringRedisSerializer());
template.setHashKeySerializer(new StringRedisSerializer());
// 2. Value 使用 Jackson 序列化为 JSON(支持对象自动转换)
GenericJackson2JsonRedisSerializer jsonSerializer = new GenericJackson2JsonRedisSerializer();
template.setValueSerializer(jsonSerializer);
template.setHashValueSerializer(jsonSerializer);
template.afterPropertiesSet();
return template;
}
}
5、业务逻辑BookService.java(缓存逻辑)
package org.example.Service;
import org.example.BookRepository.BookRepository;
import org.example.Entity.Book;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import java.util.concurrent.TimeUnit;
@Service
public class BookService {
private static final String CACHE_KEY_PREFIX = "BOOK:";
@Autowired
private BookRepository bookRepository;
@Autowired
private RedisTemplate<String , Object> redisTemplate;
int count = 0;
/*
根据id查询数据
redis缓存-数据库-写入缓存
*/
public Book getBookById(String id ){
String cacheKey = CACHE_KEY_PREFIX + id;
if (count == 0) {
redisTemplate.delete(cacheKey);
System.out.println("缓存数据预先清空");
count++;
}
//从缓存中获取数据
Book cacheBook =(Book ) redisTemplate.opsForValue().get(cacheKey);
if (cacheBook != null){
System.out.println("从redis缓存中获取数据"+cacheBook.getTitle());
return cacheBook;
}
//缓存未命中
System.out.println("缓存未命中,从数据库中获取数据");
Book book = bookRepository.findById(id);
//如果数据库有数据,写入缓存
if(book != null){
redisTemplate.opsForValue().set(cacheKey,book, 10,TimeUnit.MINUTES);
System.out.println("书籍已经写入redis:"+book.getTitle());
}
return book;
}
//更新书籍和缓存
public Book saveBook(Book book){
//将书籍保存数据库
Book savaBook= bookRepository.save(book);
//更新缓存
String cacheKey = CACHE_KEY_PREFIX + savaBook.getId();
redisTemplate.opsForValue().set(cacheKey,book,10,TimeUnit.MINUTES);
System.out.println("书籍已经更新到redis:"+book.getTitle());
return savaBook;
}
//删除书籍和缓存
public void delete(String id){
bookRepository.delete(id);
//删除缓存
String cacheKey = CACHE_KEY_PREFIX+id;
redisTemplate.delete(cacheKey);
System.out.println("书籍已经从redis中删除:"+getBookById(id).getTitle());
}
}
.out.println("书籍已经从redis中删除:"+getBookById(id).getTitle());
}
}
6、控制层BookController
package org.example.Controller;
import org.example.Entity.Book;
import org.example.Service.BookService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("api/books")
public class BookController {
@Autowired
private BookService bookService;
@GetMapping("/{id}")
public Book getBook(@PathVariable String id ){
return bookService.getBookById(id);
}
@PostMapping
public Book creatBook(@RequestBody Book book){
return bookService.saveBook(book);
}
public String deleteBook(@PathVariable String id ){
return "书籍已删除:"+id;
}
}
7、启动类
package org.example;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class BookStoreApplication {
public static void main(String[] args) {
SpringApplication.run(BookStoreApplication.class,args);
}
}
8、浏览器验证
浏览器输入
idea控制台输出
缓存数据预先清空
缓存未命中,从数据库中获取数据
书籍已经写入redis:深入理解Java虚拟机
从redis缓存中获取数据深入理解Java虚拟机
第二次没有访问数据库直接访问redis,发现第二次查询明显快于第一次
9、redis查看数据
gonghao@LAPTOP-QERLRQD4:~$ redis-cli --raw
127.0.0.1:6379> get BOOK:1
{"@class":"org.example.Entity.Book","id":"1","title":"深入理解Java虚拟机","author":"周志明","isbn":"978-7-111-12345-6","price":["java.math.BigDecimal",89.00],"description":"Java开发者必读的JVM经典书籍","category":"编程"}"
2、存储登录状态-Redis Session
使用场景
假设我们正在开发一个应用程序,用户需要登录以访问某些资源。为了管理用户会话,我们可以使用Redis来存储登录信息session和登录信息(账户密码)并给Redis Session设置过期时效,这样用户在登录信息有效期内进入页面就不再需要访问数据库
POM依赖,Redis配置一致
1、实体类User
package org.example.Entity;
import lombok.Data;
import java.io.Serializable;
@Data
public class User implements Serializable {
private static final long serialVersionUID = 1L;
private String id;
private String username;
private String password;
private String email;
private String role;
}
2、模拟数据库访问层UserRepository
package org.example.BookRepository;
import org.example.Entity.User;
import org.springframework.stereotype.Repository;
import javax.annotation.PostConstruct;
import java.util.HashMap;
import java.util.Map;
@Repository
public class UserRepository {
private Map<String , User> userDatabase = new HashMap<>();
@PostConstruct
public void init(){
User admin = new User();
admin.setId("1");
admin.setUsername("admin");
admin.setPassword("123456");
admin.setEmail("admin@bookstore.com");
admin.setRole("ADMIN");
User user = new User();
user.setId("2");
user.setUsername("user");
user.setPassword("123456");
user.setEmail("user@bookstore.com");
user.setRole("USER");
// 模拟数据库存储
userDatabase.put(admin.getUsername(), admin);
userDatabase.put(user.getUsername(), user);
System.out.println("✅ 模拟数据库用户初始化完成");
}
// 根据用户名查询
public User findByUsername(String username) {
try {
// 模拟数据库查询延迟
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
return userDatabase.get(username);
}
}
3、业务逻辑AuthService
package org.example.Service;
import org.example.BookRepository.UserRepository;
import org.example.Entity.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
@Service
public class AuthService {
private static final String USER_CACHE_PREFIX = "user:cache:";
private static final String SESSION_PREFIX = "session:";
// 用户信息缓存 30 分钟
private static final long CACHE_TIMEOUT = 30;
// 会话 30 分钟
private static final long SESSION_TIMEOUT = 30;
@Autowired
private RedisTemplate<String, Object> redisTemplate;
@Autowired
private UserRepository userRepository;
/**
* 登录验证
* 1. 先从 Redis 缓存查询用户信息
* 2. 缓存未命中则查模拟数据库
* 3. 查库后写入 Redis 缓存(30 分钟有效期)
*/
public String login(String username, String password) {
// 1. 先从 Redis 缓存查询用户信息
String cacheKey = USER_CACHE_PREFIX + username;
User user = (User) redisTemplate.opsForValue().get(cacheKey);
// 2. 缓存未命中,查模拟数据库
if (user == null) {
System.out.println("📖 缓存未命中,查询模拟数据库: " + username);
user = userRepository.findByUsername(username);
if (user == null) {
System.out.println("数据库 用户不存在: " + username);
return null;
}
// 3. 写入 Redis 缓存,设置 30 分钟有效期
redisTemplate.opsForValue().set(cacheKey, user, CACHE_TIMEOUT, TimeUnit.MINUTES);
System.out.println("📝 用户信息已缓存到 Redis: " + username);
} else {
System.out.println("✅ 用户在半小时内登录: " + username);
}
// 4. 验证密码
if (!user.getPassword().equals(password)) {
System.out.println("密码错误: " + username);
return null;
}
// 5. 生成 Token
String token = UUID.randomUUID().toString().replace("-", "");
// 6. 存储会话到 Redis(存储用户信息)
String sessionKey = SESSION_PREFIX + token;
redisTemplate.opsForValue().set(sessionKey, user, SESSION_TIMEOUT, TimeUnit.MINUTES);
System.out.println("登录成功: " + username);
return token;
}
}
4、控制层AuthController
package org.example.Controller;
import lombok.extern.slf4j.Slf4j;
import org.example.Entity.User;
import org.example.Service.AuthService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.HashMap;
import java.util.Map;
@Slf4j
@RestController
@RequestMapping("/auth")
public class AuthController {
@Autowired
private AuthService authService;
@GetMapping("/login")
public Map<String, Object> login(@RequestParam String username,
@RequestParam String password) {
Map<String, Object> result = new HashMap<>();
String token = authService.login(username, password);
log.info("登录结果: {}", token);
if (token != null) {
result.put("code", 200);
result.put("message", "登录成功");
result.put("token", token);
} else {
result.put("code", 401);
result.put("message", "用户名或密码错误");
}
return result;
}
}
5、浏览器验证
idea输出
✅ 用户在半小时内登录: admin
登录成功: admin
2026-07-21 17:27:52.009 INFO 32488 --- [nio-8080-exec-1] org.example.Controller.AuthController : 登录结果: 96a0b89e40f643e4b141f2020498b88c
✅ 用户在半小时内登录: admin
第一次登录查询的是模拟数据库,速度较慢,将用户登录信息存入redis。第二次登录查询redis,速度明显提升。
6、Redis查看数据
127.0.0.1:6379> get user:cache:admin
{"@class":"org.example.Entity.User","id":"1","username":"admin","password":"123456","email":"admin@bookstore.com","role":"ADMIN"}