redis 在用户管理系统中的典型应用场景
结合你的用户增删改查接口,以下是 redis 的实用场景和具体实现方案:
场景 | 作用 | 实现方案 |
---|---|---|
用户信息缓存 | 减少数据库压力,加速查询响应 | 使用 spring cache + redis 注解缓存 |
登录 token 存储 | 分布式 session 或 jwt token 管理 | 将 token 与用户信息绑定,设置过期时间 |
接口限流 | 防止恶意刷接口 | 基于 redis 计数器实现滑动窗口限流 |
重复提交拦截 | 防止用户重复提交表单 | 用 redis 存储请求唯一标识,设置短期过期 |
热点数据预加载 | 提前缓存高频访问数据 | 定时任务 + redis 存储 |
mac m1 安装 redis 详细步骤
1. 通过 homebrew 安装 redis
# 安装 homebrew(如果尚未安装) /bin/bash -c "$(curl -fssl https://raw.githubusercontent.com/homebrew/install/head/install.sh)" # 安装 redis brew install redis
2. 启动 redis 服务
# 前台启动(测试用,ctrl+c 退出) redis-server # 后台启动(推荐) brew services start redis
3. 验证安装
# 连接 redis 客户端 redis-cli ping # 应返回 "pong"
spring boot 3 整合 redis
1. 添加依赖
在 pom.xml
中:
<!-- spring cache 核心依赖 --> <dependency> <groupid>org.springframework.boot</groupid> <artifactid>spring-boot-starter-cache</artifactid> </dependency> <!-- redis 驱动 --> <dependency> <groupid>org.springframework.boot</groupid> <artifactid>spring-boot-starter-data-redis</artifactid> </dependency> <dependency> <groupid>com.fasterxml.jackson.core</groupid> <artifactid>jackson-databind</artifactid> </dependency>
2. 配置 redis 连接
application.yml
:
spring: data: redis: host: localhost port: 6379 # password: your-password # 如果设置了密码 lettuce: pool: max-active: 8 max-idle: 8
3. 示例
配置类
package com.example.spring_demo01.config; import org.springframework.cache.cachemanager; import org.springframework.context.annotation.bean; import org.springframework.context.annotation.configuration; import org.springframework.data.redis.cache.rediscacheconfiguration; import org.springframework.data.redis.cache.rediscachemanager; import org.springframework.data.redis.connection.redisconnectionfactory; import org.springframework.data.redis.core.redistemplate; import org.springframework.data.redis.serializer.*; import java.time.duration; @configuration public class redisconfig { // 配置 redistemplate @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 结构序列化 template.sethashkeyserializer(new stringredisserializer()); template.sethashvalueserializer(new genericjackson2jsonredisserializer()); return template; } // 配置缓存管理器 @bean public cachemanager cachemanager(redisconnectionfactory factory) { rediscacheconfiguration config = rediscacheconfiguration.defaultcacheconfig() .serializekeyswith(redisserializationcontext.serializationpair.fromserializer(new stringredisserializer())) .serializevalueswith(redisserializationcontext.serializationpair.fromserializer(new genericjackson2jsonredisserializer())) .entryttl(duration.ofminutes(30)); // 设置默认过期时间 return rediscachemanager.builder(factory) .cachedefaults(config) .build(); } }
接口限流工具类
package com.example.spring_demo01.utils; import org.springframework.beans.factory.annotation.autowired; import org.springframework.data.redis.core.redistemplate; import org.springframework.stereotype.component; import java.util.uuid; import java.util.concurrent.timeunit; @component public class ratelimiter { @autowired private redistemplate<string, object> redistemplate; public boolean allowrequest(string userid) { string key = "rate_limit:" + userid; long now = system.currenttimemillis(); long windowms = 60_000; // 1 分钟 // 移除窗口外的请求记录 redistemplate.opsforzset().removerangebyscore(key, 0, now - windowms); // 统计当前窗口内请求数 long count = redistemplate.opsforzset().zcard(key); if (count != null && count >= 10) { return false; // 超过限制 } // 记录本次请求 redistemplate.opsforzset().add(key, uuid.randomuuid().tostring(), now); redistemplate.expire(key, windowms, timeunit.milliseconds); return true; } }
实体类
package com.example.spring_demo01.entity; import com.baomidou.mybatisplus.annotation.*; import com.fasterxml.jackson.annotation.jsonignoreproperties; import lombok.data; import java.io.serializable; @data @tablename("user") @jsonignoreproperties(ignoreunknown = true) // 防止 json 反序列化问题 public class user implements serializable { // 实现 serializable @tableid(type = idtype.auto) // 主键自增 private long id; private string name; private integer age; private string email; }
service层
package com.example.spring_demo01.service.impl; import com.baomidou.mybatisplus.extension.service.impl.serviceimpl; import com.example.spring_demo01.entity.user; import com.example.spring_demo01.mapper.usermapper; import com.example.spring_demo01.service.userservice; import org.springframework.cache.annotation.cacheevict; import org.springframework.cache.annotation.cacheable; import org.springframework.stereotype.service; import java.io.serializable; @service public class userserviceimpl extends serviceimpl<usermapper, user> implements userservice { // 对 mybatis plus 的 getbyid 方法添加缓存 @cacheable(value = "user", key = "#id") @override public user getbyid(serializable id) { return super.getbyid(id); } // 更新时清除缓存 @cacheevict(value = "user", key = "#entity.id") @override public boolean updatebyid(user entity) { return super.updatebyid(entity); } // 删除时清除缓存 @cacheevict(value = "user", key = "#id") @override public boolean removebyid(serializable id) { return super.removebyid(id); } }
controller层
package com.example.spring_demo01.controller; import com.baomidou.mybatisplus.core.conditions.query.querywrapper; import com.baomidou.mybatisplus.extension.plugins.pagination.page; import com.example.spring_demo01.annotation.adminonly; import com.example.spring_demo01.entity.user; import com.example.spring_demo01.service.userservice; import com.example.spring_demo01.utils.ratelimiter; import lombok.extern.slf4j.slf4j; import org.springframework.beans.factory.annotation.autowired; import org.springframework.data.redis.core.redistemplate; import org.springframework.web.bind.annotation.*; import java.time.duration; import java.util.list; import java.util.uuid; @slf4j @restcontroller @requestmapping("/user") public class usercontroller { @autowired private userservice userservice; @autowired private redistemplate<string, object> redistemplate; @autowired private ratelimiter ratelimiter; // ------------------------------ 增 ------------------------------ @postmapping public string adduser(@requestbody user user, @requestheader string clientid) { string key = "submit_lock:" + clientid + ":" + user.hashcode(); // 10秒内不允许重复提交 boolean success = redistemplate.opsforvalue() .setifabsent(key, "", duration.ofseconds(10)); if (boolean.false.equals(success)) { throw new runtimeexception("请勿重复提交"); } userservice.save(user); return "新增成功"; } // ------------------------------ 删 ------------------------------ @deletemapping("/{id}") public string deleteuser(@pathvariable long id) { userservice.removebyid(id); return "删除成功"; } @deletemapping("/batch") public string deletebatch(@requestbody list<long> ids) { userservice.removebyids(ids); return "批量删除成功"; } // ------------------------------ 改 ------------------------------ @putmapping public string updateuser(@requestbody user user) { userservice.updatebyid(user); return "更新成功"; } // ------------------------------ 查 ------------------------------ @getmapping("/{id}") @adminonly public user getuserbyid(@pathvariable long id) { return userservice.getbyid(id); } @getmapping("/list") public list<user> listusers( @requestparam(required = false) string name, @requestparam(required = false) integer age) { querywrapper<user> wrapper = new querywrapper<>(); if (name != null) { wrapper.like("name", name); // 模糊查询姓名 } if (age != null) { wrapper.eq("age", age); // 精确查询年龄 } return userservice.list(wrapper); } @getmapping("/page") public page<user> pageusers( @requestparam(defaultvalue = "1") integer pagenum, @requestparam(defaultvalue = "10") integer pagesize, @requestheader(value = "authorization") string token) { // 从 token 中获取用户id log.info("token:{}", token); log.info("user:{}", redistemplate.opsforvalue().get(token.split(" ")[1])); user user = (user) redistemplate.opsforvalue().get(token.split(" ")[1]); if (user == null) throw new runtimeexception("未登录"); // 限流校验 if (!ratelimiter.allowrequest("page_" + user.getid())) { throw new runtimeexception("请求过于频繁"); } return userservice.page(new page<>(pagenum, pagesize)); } // ------------------------------ other ------------------------------ @getmapping("/error") public string geterror() { throw new runtimeexception(); } @postmapping("/login") public string login(@requestbody user user) { log.info("login user:{}", user); // 验证用户逻辑(示例简化) user dbuser = userservice.getone(new querywrapper<user>() .eq("id", user.getid()) .eq("name", user.getname())); if (dbuser == null) { throw new runtimeexception("登录失败"); } // 生成 token 并存储 string token = "token_" + uuid.randomuuid(); redistemplate.opsforvalue().set( token, dbuser, duration.ofminutes(30) ); return token; } }
在启动类添加注解:
package com.example.spring_demo01; import org.mybatis.spring.annotation.mapperscan; import org.springframework.boot.springapplication; import org.springframework.boot.autoconfigure.springbootapplication; import org.springframework.boot.web.servlet.servletcomponentscan; import org.springframework.cache.annotation.enablecaching; @springbootapplication @mapperscan("com.example.spring_demo01.mapper") @servletcomponentscan // 启用 servlet 组件扫描(如 filter、servlet) @enablecaching // 启动缓存,redis使用 public class springdemo01application { public static void main(string[] args) { springapplication.run(springdemo01application.class, args); } }
常见问题排查
q1: 连接 redis 超时
- 检查服务状态:运行
redis-cli ping
确认 redis 是否正常运行 - 查看端口占用:
lsof -i :6379
- 关闭防火墙:
sudo ufw allow 6379
q2: spring boot 无法注入 redistemplate
- 确认配置类:添加
@enablecaching
和@configuration
- 检查序列化器:显式配置序列化方式避免 classcastexception
@configuration public class redisconfig { @bean public redistemplate<string, object> redistemplate(redisconnectionfactory factory) { redistemplate<string, object> template = new redistemplate<>(); template.setconnectionfactory(factory); template.setkeyserializer(new stringredisserializer()); template.setvalueserializer(new genericjackson2jsonredisserializer()); return template; } }
总结
通过 redis 你可以为项目快速实现:
- 高性能缓存层 - 降低数据库负载
- 分布式会话管理 - 支持横向扩展
- 精细化流量控制 - 保障系统稳定性
到此这篇关于springboot + mybatis plus 整合 redis的详细步骤的文章就介绍到这了,更多相关springboot mybatis plus 整合 redis内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!
发表评论