【Redis】三、在springboot中应用redis

目录

一、引入依赖

二、设置redis相关配置

三、准备测试项目框架

四、注册redis中间件

五、实现缓存逻辑

六、查询测试


今天在springboot中学习如何应用redis,实现用户信息管理的缓存中间件实现。

一、引入依赖

redis的客户端主要有Jedis 和 Lettuce两种,Spring Boot 2.x 及以上版本默认使用 Lettuce 作为 Redis 客户端,能提供更好的异步支持,且内置连接池,配置简单,无需额外依赖。

复制代码
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>

二、设置redis相关配置

在application.yml中配置如下信息。

复制代码
  redis:
    host: localhost       # Redis 服务器地址
    port: 6379            # Redis 服务器端口
    password: ""          # Redis 密码(若有)
    database: 0           # 默认使用的数据库索引(0-15)
    timeout: 5000         # 连接超时时间(毫秒)

三、准备测试项目框架

为了测试springboot应用redis,我们创建一个简单的关于用户管理的模块。包含下面的信息:

sql表

sql 复制代码
CREATE TABLE users (
    id INT PRIMARY KEY AUTO_INCREMENT,
    username VARCHAR(50) NOT NULL UNIQUE,
    password_hash VARCHAR(255) NOT NULL,
    full_name VARCHAR(100) NOT NULL,
    phone_number VARCHAR(20) UNIQUE,
    email VARCHAR(100) NOT NULL UNIQUE,
    score_rank INT DEFAULT 0,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
);    

userEntity

java 复制代码
package com.naihe.redistest.entity;

import com.baomidou.mybatisplus.annotation.*;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.AllArgsConstructor;

import java.time.LocalDateTime;

@Data
@NoArgsConstructor
@AllArgsConstructor
@TableName("users")
public class UserEntity {
    @TableId(value = "id", type = IdType.AUTO)
    private Integer id;
    private String username;
    @TableField("password_hash")
    private String passwordHash;
    @TableField("full_name")
    private String fullName;
    @TableField("phone_number")
    private String phoneNumber;
    private String email;
    @TableField("score_rank")
    private Integer scoreRank;
    @TableField(value = "created_at", fill = FieldFill.INSERT)
    private LocalDateTime createdAt;
    @TableField(value = "updated_at", fill = FieldFill.UPDATE)
    private LocalDateTime updatedAt;
}

controller

java 复制代码
package com.naihe.redistest.controller;

import com.naihe.redistest.pojo.dto.RegisterDTO;
import com.naihe.redistest.service.UserService;
import com.naihe.redistest.utils.Result;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import java.security.NoSuchAlgorithmException;

@Slf4j
@Component
@Controller
@RestController
@RequestMapping("/user")
public class UserController {
    @Autowired
    UserService userService;

    /**
     * 用户注册接口,接收用户注册信息并处理
     *
     * @param registerBean 用户注册信息的传输对象
     * @return Result 返回操作结果
     */
    @PostMapping("/register")
    public Result register(@RequestBody RegisterDTO registerBean){
        userService.insertUser(registerBean);
        return Result.ok().data("msg", "注册成功");
    }

    /**
     * 查询用户分数
     *
     * @param userId 用户的id
     * @return Result 返回操作结果
     */
    @GetMapping("/getScore/{userId}")
    public Result getScore(@PathVariable String userId) {
        Integer score = userService.getScore(userId);
        return Result.ok().data("score", score);
    }

}

service

java 复制代码
package com.naihe.redistest.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.naihe.redistest.entity.UserEntity;
import com.naihe.redistest.mapper.UserMapper;
import com.naihe.redistest.pojo.dto.RegisterDTO;
import com.naihe.redistest.service.UserService;
import org.springframework.beans.BeanUtils;
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 UserServiceImpl implements UserService {

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    private static final String USER_SCORE_KEY = "user:score:";
    private static final long CACHE_EXPIRE_TIME = 30; // 缓存30分钟

    @Override
    public void insertUser(RegisterDTO registerBean) {
        if (userMapper.selectOne(new QueryWrapper<UserEntity>().eq("username", registerBean.getUsername())) != null) {
            throw new RuntimeException(registerBean.getUsername() + "已存在");
        }
        UserEntity userEntity = new UserEntity();
        BeanUtils.copyProperties(registerBean,userEntity);
        userMapper.insert(userEntity);
    }
}

添加测试数据

四、注册redis中间件

java 复制代码
package com.naihe.redistest.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 factory) {
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(factory);
        
        // 设置 key 的序列化方式
        template.setKeySerializer(new StringRedisSerializer());
        // 设置 value 的序列化方式(JSON 格式)
        template.setValueSerializer(new GenericJackson2JsonRedisSerializer());
        
        // 设置 hash key 和 value 的序列化方式
        template.setHashKeySerializer(new StringRedisSerializer());
        template.setHashValueSerializer(new GenericJackson2JsonRedisSerializer());
        
        template.afterPropertiesSet();
        return template;
    }
}

五、实现缓存逻辑

在service服务层中应用,查询用户分数时,优先从redis中查找,若不存在,则从mysql数据库中查找后,添加到redis中。

java 复制代码
package com.naihe.redistest.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.naihe.redistest.entity.UserEntity;
import com.naihe.redistest.mapper.UserMapper;
import com.naihe.redistest.pojo.dto.RegisterDTO;
import com.naihe.redistest.service.UserService;
import org.springframework.beans.BeanUtils;
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 UserServiceImpl implements UserService {

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    private static final String USER_SCORE_KEY = "user:score:";
    private static final long CACHE_EXPIRE_TIME = 30; // 缓存30分钟

    @Override
    public void insertUser(RegisterDTO registerBean) {
        if (userMapper.selectOne(new QueryWrapper<UserEntity>().eq("username", registerBean.getUsername())) != null) {
            throw new RuntimeException(registerBean.getUsername() + "已存在");
        }
        UserEntity userEntity = new UserEntity();
        BeanUtils.copyProperties(registerBean,userEntity);
        userMapper.insert(userEntity);
    }

    public Integer getScore(String userId) {
        String key = USER_SCORE_KEY + userId;

        // 先从Redis获取缓存数据
        Integer score = (Integer) redisTemplate.opsForValue().get(key);

        if (score != null) {
            return score;
        }

        // 缓存未命中,从数据库获取
        UserEntity user = userMapper.selectById(userId);
        if (user == null) {
            throw new RuntimeException("用户不存在");
        }

        score = user.getScoreRank();

        // 将数据存入Redis缓存
        redisTemplate.opsForValue().set(key, score, CACHE_EXPIRE_TIME, TimeUnit.MINUTES);

        return score;
    }
}

六、查询测试

现在我们使用postman对接口进行测试,查询用户分数,检测redis是否成功应用。

首次查询我们可以看到,差不多用了1秒多的时间,此次查询没有在redis中查询到信息,所以会将该用户的分数存储进redis中。

我们再次查询该用户。

可以看到,这次的查询速度快了许多,达到了38ms,至此,我们完成了redis在springboot的简单应用,在后续更为复杂的业务可以使用更多的redis数据结构。

相关推荐
Elastic 中国社区官方博客5 小时前
在 Elasticsearch 中使用 Mistral Chat completions 进行上下文工程
大数据·数据库·人工智能·elasticsearch·搜索引擎·ai·全文检索
编程爱好者熊浪6 小时前
两次连接池泄露的BUG
java·数据库
cr7xin7 小时前
缓存三大问题及解决方案
redis·后端·缓存
摇滚侠8 小时前
Spring Boot3零基础教程,Spring Boot 应用打包成 exe 可执行文件,笔记91 笔记92 笔记93
linux·spring boot·笔记
TDengine (老段)8 小时前
TDengine 字符串函数 CHAR 用户手册
java·大数据·数据库·物联网·时序数据库·tdengine·涛思数据
qq7422349848 小时前
Python操作数据库之pyodbc
开发语言·数据库·python
姚远Oracle ACE8 小时前
Oracle 如何计算 AWR 报告中的 Sessions 数量
数据库·oracle
Dxy12393102169 小时前
MySQL的SUBSTRING函数详解与应用
数据库·mysql
码力引擎9 小时前
【零基础学MySQL】第十二章:DCL详解
数据库·mysql·1024程序员节
杨云龙UP9 小时前
【MySQL迁移】MySQL数据库迁移实战(利用mysqldump从Windows 5.7迁至Linux 8.0)
linux·运维·数据库·mysql·mssql