【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数据结构。

相关推荐
长勺17 分钟前
Spring Boot自动装配原理
java·spring boot·后端
清幽竹客1 小时前
Lua 脚本在 Redis 中的运用-23(Lua 脚本语法教程)
redis·lua
编程乐学(Arfan开发工程师)1 小时前
28、请求处理-【源码分析】-请求映射原理
java·前端·spring boot·后端·spring
比特森林探险记2 小时前
MySQL 大战 PostgreSQL
数据库·mysql·postgresql
小哥哥咯2 小时前
Oracle/openGauss中,DATE/TIMESTAMP与数字日期/字符日期比较
数据库
小何慢行2 小时前
PostgreSQL如何更新和删除表数据
数据库·postgresql
代码的余温2 小时前
Solr搜索:比传统数据库强在哪?
数据库·全文检索·solr
阿楠不会敲代码2 小时前
分布式数据库备份实践
数据库·分布式
gsls2008082 小时前
阿里云云效对接SDK获取流水线制品
数据库
菠萝012 小时前
分布式不同数据的一致性模型
数据库·c++·分布式·后端