redis常用场景项目简介-01数据缓存-02存储登录状态

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"}
相关推荐
海兰6 小时前
【高速缓存】RedisVL 高级查询(全文搜索、混合搜索和 多向量搜索)
数据库·人工智能·redis·缓存
DBA_G6 小时前
GBase 8s数据库大对象存储详解
数据库
sbjdhjd6 小时前
SQL 注入零基础详解:原理、手工注入流程与 Sqli-Labs 靶场实战1~5关和第9关思路
数据库·sql·计算机网络·web安全·网络安全·网络攻击模型·安全架构
Tencent_TCB7 小时前
腾讯云 CloudBase 登上 WAIC:我们为 Agent 重新设计了云的生产线
网络·数据库·腾讯云
数智化管理手记8 小时前
预算控制手工核对效率低?预算控制数字化落地实操如何做?
大数据·网络·数据库·人工智能·数据挖掘
MXsoft6188 小时前
成熟的自动化运维平台是什么样的?
运维·数据库·自动化
吴声子夜歌8 小时前
MongoDB 4.x——合理使用索引(二)
数据库·mongodb
慾玄8 小时前
sql注入靶场1-5,9关
数据库·sql
记录者t8 小时前
redis常见问题:大key
数据库·redis