【AI学习笔记】用AI生成spring boot + redis

环境: WIN11 家庭版 | IDEA2023 | JDK17 | MAVEN3.6+ | redis for windows

1."我:请帮我生成一个spring boot 项目"

2.deepseek:

复制代码
打开 IDEA,点击 New Project
选择 Spring Initializr
Name: 项目名称(如 demo-project)
Location: 项目保存路径
Language: Java
Type: Maven 或 Gradle
Group: 包名(如 com.example)
Artifact: 项目标识(如 demo)
Package name: 自动生成(如 com.example.demo)
JDK: 选择 JDK 17
Java: 17
选择依赖(根据需求选择):
Spring Web - Web 开发
Spring Boot DevTools - 开发工具
Lombok - 简化代码
Spring Data JPA - 数据库操作
MySQL Driver - MySQL 数据库
Thymeleaf - 模板引擎
点击 Create 完成项目创建

**项目结构:**

demo-project/
├── src/
│   ├── main/
│   │   ├── java/
│   │   │   └── com/example/demo/
│   │   │       ├── DemoApplication.java
│   │   │       ├── controller/
│   │   │       ├── service/
│   │   │       └── repository/
│   │   └── resources/
│   │       ├── application.properties
│   │       ├── static/
│   │       └── templates/
├── pom.xml
└── README.md

package com.example.demo.controller;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class HelloController {

    @GetMapping("/hello")
    public String hello() {
        return "Hello, Spring Boot with JDK 17!";
    }
    
    @GetMapping("/info")
    public String info() {
        return "项目运行在 JDK " + System.getProperty("java.version");
    }
}

配置application.properties/application.yml

复制代码
properties
# 服务器配置
server.port=8080
server.servlet.context-path=/

# 应用配置
spring.application.name=demo-project

# 日志配置
logging.level.com.example.demo=DEBUG

运行项目

打开 DemoApplication.java

点击 main 方法旁边的运行按钮

或使用快捷键:Ctrl+Shift+F10

测试应用

在浏览器中访问:

http://localhost:8080/hello

http://localhost:8080/info

3."在上述项目中添加redis"

4.deepseek:

添加 Redis 依赖

复制代码
<dependencies>
    <!-- Spring Boot Data Redis -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-redis</artifactId>
    </dependency>
    
    <!-- Redis 连接池 -->
    <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>

配置 redis - application.properties

复制代码
# redis 基本配置
spring.redis.host=localhost
spring.redis.port=6379
spring.redis.password=
spring.redis.database=0

# 连接池配置
spring.redis.lettuce.pool.max-active=8
spring.redis.lettuce.pool.max-idle=8
spring.redis.lettuce.pool.min-idle=0
spring.redis.lettuce.pool.max-wait=-1ms

# 连接超时
spring.redis.timeout=2000ms

新增redis配置类

创建 Redis 配置类来自定义序列化方式

复制代码
package com.example.demo.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;

@Configuration
public class RedisConfig {

    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory connectionFactory) {
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(connectionFactory);
        
        // 设置 key 的序列化器
        template.setKeySerializer(new StringRedisSerializer());
        template.setHashKeySerializer(new StringRedisSerializer());
        
        // 设置 value 的序列化器
        template.setValueSerializer(new GenericJackson2JsonRedisSerializer());
        template.setHashValueSerializer(new GenericJackson2JsonRedisSerializer());
        
        template.afterPropertiesSet();
        return template;
    }
}

创建redis服务类

复制代码
package com.example.demo.service;

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 RedisService {

    @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 redisTemplate.delete(key);
    }

    /**
     * 判断 key 是否存在
     */
    public Boolean hasKey(String key) {
        return redisTemplate.hasKey(key);
    }

    /**
     * 设置过期时间
     */
    public Boolean expire(String key, long timeout, TimeUnit unit) {
        return redisTemplate.expire(key, timeout, unit);
    }

    /**
     * 获取过期时间
     */
    public Long getExpire(String key) {
        return redisTemplate.getExpire(key, TimeUnit.SECONDS);
    }
}

创建redis测试方法

复制代码
package com.example.demo.controller;

import com.example.demo.service.RedisService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

@RestController
@RequestMapping("/redis")
public class RedisController {

    @Autowired
    private RedisService redisService;

    /**
     * 设置缓存
     */
    @PostMapping("/set")
    public String set(@RequestParam String key, @RequestParam String value) {
        redisService.set(key, value);
        return "设置成功: " + key + " = " + value;
    }

    /**
     * 设置带过期时间的缓存
     */
    @PostMapping("/setWithExpire")
    public String setWithExpire(@RequestParam String key, 
                               @RequestParam String value,
                               @RequestParam long timeout) {
        redisService.set(key, value, timeout, TimeUnit.SECONDS);
        return "设置成功: " + key + " = " + value + ", 过期时间: " + timeout + "秒";
    }

    /**
     * 获取缓存
     */
    @GetMapping("/get/{key}")
    public Object get(@PathVariable String key) {
        Object value = redisService.get(key);
        if (value == null) {
            return "键不存在: " + key;
        }
        return value;
    }

    /**
     * 删除缓存
     */
    @DeleteMapping("/delete/{key}")
    public String delete(@PathVariable String key) {
        Boolean result = redisService.delete(key);
        return result ? "删除成功: " + key : "删除失败,键不存在: " + key;
    }

    /**
     * 检查键是否存在
     */
    @GetMapping("/hasKey/{key}")
    public String hasKey(@PathVariable String key) {
        Boolean exists = redisService.hasKey(key);
        return exists ? "键存在: " + key : "键不存在: " + key;
    }

    /**
     * 获取系统信息
     */
    @GetMapping("/info")
    public Map<String, Object> getRedisInfo() {
        Map<String, Object> info = new HashMap<>();
        info.put("javaVersion", System.getProperty("java.version"));
        info.put("redisStatus", "已连接");
        
        // 测试 Redis 连接
        try {
            redisService.set("test_connection", "success", 10, TimeUnit.SECONDS);
            info.put("redisTest", "连接正常");
        } catch (Exception e) {
            info.put("redisTest", "连接失败: " + e.getMessage());
        }
        
        return info;
    }
}

创建用户对象

复制代码
package com.example.demo.model;

import java.io.Serializable;
import java.time.LocalDateTime;

public class User implements Serializable {
    private Long id;
    private String username;
    private String email;
    private LocalDateTime createTime;

    // 构造方法
    public User() {}
    
    public User(Long id, String username, String email) {
        this.id = id;
        this.username = username;
        this.email = email;
        this.createTime = LocalDateTime.now();
    }

    // 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 LocalDateTime getCreateTime() { return createTime; }
    public void setCreateTime(LocalDateTime createTime) { this.createTime = createTime; }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", username='" + username + '\'' +
                ", email='" + email + '\'' +
                ", createTime=" + createTime +
                '}';
    }
}

redis缓存示例

复制代码
package com.example.demo.service;

import com.example.demo.model.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.concurrent.TimeUnit;

@Service
public class UserCacheService {

    @Autowired
    private RedisService redisService;

    private static final String USER_KEY_PREFIX = "user:";
    private static final long USER_CACHE_TIMEOUT = 30; // 30分钟

    /**
     * 缓存用户信息
     */
    public void cacheUser(User user) {
        String key = USER_KEY_PREFIX + user.getId();
        redisService.set(key, user, USER_CACHE_TIMEOUT, TimeUnit.MINUTES);
    }

    /**
     * 从缓存获取用户信息
     */
    public User getCachedUser(Long userId) {
        String key = USER_KEY_PREFIX + userId;
        Object obj = redisService.get(key);
        if (obj instanceof User) {
            return (User) obj;
        }
        return null;
    }

    /**
     * 删除用户缓存
     */
    public void removeUserFromCache(Long userId) {
        String key = USER_KEY_PREFIX + userId;
        redisService.delete(key);
    }
}

测试用户缓存

复制代码
package com.example.demo.controller;

import com.example.demo.model.User;
import com.example.demo.service.UserCacheService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/user")
public class UserController {

    @Autowired
    private UserCacheService userCacheService;

    /**
     * 缓存用户信息
     */
    @PostMapping("/cache")
    public String cacheUser(@RequestParam Long id, 
                           @RequestParam String username,
                           @RequestParam String email) {
        User user = new User(id, username, email);
        userCacheService.cacheUser(user);
        return "用户缓存成功: " + user;
    }

    /**
     * 获取缓存用户
     */
    @GetMapping("/cache/{id}")
    public Object getCachedUser(@PathVariable Long id) {
        User user = userCacheService.getCachedUser(id);
        if (user == null) {
            return "用户未在缓存中找到: " + id;
        }
        return user;
    }

    /**
     * 删除缓存用户
     */
    @DeleteMapping("/cache/{id}")
    public String removeCachedUser(@PathVariable Long id) {
        userCacheService.removeUserFromCache(id);
        return "用户缓存已删除: " + id;
    }
}

备注:windows家庭版无法使用docker部署redis,请使用windows专业版、教育版等。

综上,一个简单的springboot + redis框架已经完成,亲测可用,后续将继续扩展集群、分布式,日志、权限等模块

在此记录相关知识点:

spring 两大特点 : IOC/控制反转和依赖注入

ioc个人简单理解:

以前想用对象,我需要 A a = new A;

IOC:先将对象通过配置注解的方式标记,需要使用时,直接使用对象,不需要new,

官方说法是,可以解耦,自我理解为:我先声明我有这个玩意,哪里要用,直接拿来用即可,无需一遍遍的new。

AOP 面向切面,这个理解简单一些,我可以再固定的位置定义切入点,定义后,我可以操作切入点前后执行方法

可以定义before(方法前)、After(方法后)、After-returning(方法执行成功后) After-throwing(方法执行异常后)、Around(环绕)

Around特殊点,可以设置前后执行方法,一般处理事务常用,处理前开启事务,处理后提交事务。

redis 雪崩,击穿,穿透 ,主要是前两者 是key失效,或者redis服务挂了导致请求直接注入数据库,给数据库干蒙蔽。

后者是请求了一个未知key ,要么把null写进redis,要么使用布隆过滤器,原理是预加载,把已知的Key全部缓存进去,如果不存在,直接返回空。

个人理解为,主机启动前先加载缓存数据至redis。

前两者解决方案:雪崩的,设置差异化过期时间,也就是设置失效时间时,给个随机码,每个key不一致,这种情况下,可以避免同时且大量失效。

也可以部署redis集群+哨兵、熔断、服务降级、兜底返回等这个太长了以后写。

击穿的,参照微博热点时间,同一时间大量请求指向一个key,好巧不巧,key失效了,结果就是数据库炸了,现象就是,用户点着没反应,要么报错

这个解决方案查了一下,热点事件一般会轮换设置长期生效,当一个事件不再是热点,则设置短期,当一个事件登上热点,触发设置长期。

另一个就是互斥锁,redis的setnx命令 或 redission(分布式锁)

当发现key失效后,请求key设置setnx成功(lock:key1),并给一个超时时间(5s),然后去查数据库,重新设置缓存,然后删除lock

这个过程中,其他请求发现key失效后,先尝试lock,但因为互斥,所以lock失败,这个时候对方会重新发起请求,或者直接给一个失败结果,主要是保证不会击穿redis,直接将大量请求放到数据库。

相关推荐
来自嵌入式的zyz3 小时前
STM32项目实战/PID算法学习:编码电机闭环控制实现控速+位置控制、倒立摆实现
stm32·嵌入式硬件·学习·控制·pid
繁花与尘埃3 小时前
列表标签之有序标签(本文为个人学习笔记,内容整理自哔哩哔哩UP主【非学者勿扰】的公开课程。 > 所有知识点归属原作者,仅作非商业用途分享)
笔记·学习
lljss20203 小时前
5. 神经网络的学习
人工智能·神经网络·学习
MYX_3094 小时前
第五章 神经网络的优化
pytorch·深度学习·神经网络·学习
Starry_hello world4 小时前
Linux 进程地址空间
linux·笔记·有问必答
junnhwan4 小时前
【苍穹外卖笔记】Day05--Redis入门与店铺营业状态设置
java·数据库·redis·笔记·后端·苍穹外卖
Zzz 小生4 小时前
**编程基础学习(二)-C语言变量、控制结构和函数
笔记·学习
金水谣4 小时前
10.12考研笔记
笔记
thginWalker4 小时前
使用Spring Boot构建Web服务层
spring boot