当前位置: 首页 > article >正文

Spring Boot + Redis实战:用opsForHash和opsForValue分别搞定商品详情页和用户会话缓存

Spring Boot与Redis深度整合电商场景下的缓存架构实战在电商系统的高并发场景中缓存设计直接决定了用户体验和系统稳定性。商品详情页作为流量最集中的页面之一其缓存策略需要兼顾数据完整性和访问效率而用户会话管理则要求快速验证和低延迟响应。本文将基于Spring Boot与Redis的深度整合通过opsForHash和opsForValue两种数据结构的对比实践展示如何构建高性能的电商缓存体系。1. 环境准备与基础配置1.1 依赖引入与连接配置首先在pom.xml中添加必要的Spring Data Redis依赖dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-data-redis/artifactId /dependency配置application.yml中的Redis连接参数spring: redis: host: 127.0.0.1 port: 6379 password: yourpassword lettuce: pool: max-active: 8 max-idle: 8 min-idle: 21.2 RedisTemplate定制化配置默认的RedisTemplate使用JDK序列化会导致可读性差和兼容性问题建议自定义配置Configuration public class RedisConfig { Bean public RedisTemplateString, Object redisTemplate( RedisConnectionFactory connectionFactory) { RedisTemplateString, Object template new RedisTemplate(); template.setConnectionFactory(connectionFactory); // 使用String序列化key template.setKeySerializer(new StringRedisSerializer()); // 使用Jackson序列化value template.setValueSerializer(new GenericJackson2JsonRedisSerializer()); // 对hash key/value单独设置序列化 template.setHashKeySerializer(new StringRedisSerializer()); template.setHashValueSerializer(new GenericJackson2JsonRedisSerializer()); return template; } }提示Jackson序列化需要确保实体类有无参构造函数否则反序列化时会报错2. 商品详情页的Hash结构缓存方案2.1 为什么选择Hash结构商品详情页通常包含数十个字段标题、价格、库存、规格等使用String类型整体存储会导致修改单个字段需要读取整个对象网络传输数据量大无法对特定字段做原子操作Hash结构的优势在于支持字段级读写内存占用更优天然适合对象存储2.2 商品模型与缓存实现定义商品实体类Data AllArgsConstructor NoArgsConstructor public class Product { private Long id; private String name; private BigDecimal price; private Integer stock; private ListString specs; private String description; }实现缓存服务Service public class ProductCacheService { Autowired private RedisTemplateString, Object redisTemplate; private static final String PRODUCT_KEY_PREFIX product:; public void cacheProductDetails(Product product) { String key PRODUCT_KEY_PREFIX product.getId(); redisTemplate.opsForHash().putAll(key, BeanUtil.beanToMap(product)); redisTemplate.expire(key, 2, TimeUnit.HOURS); // 设置过期时间 } public Product getProductDetails(Long productId) { String key PRODUCT_KEY_PREFIX productId; MapObject, Object entries redisTemplate.opsForHash().entries(key); return BeanUtil.mapToBean(entries, Product.class, true); } public void updateProductPrice(Long productId, BigDecimal newPrice) { String key PRODUCT_KEY_PREFIX productId; redisTemplate.opsForHash().put(key, price, newPrice.toString()); } }2.3 高级特性应用部分字段更新public void partialUpdate(Long productId, MapString, Object updates) { String key PRODUCT_KEY_PREFIX productId; redisTemplate.opsForHash().putAll(key, updates); }原子计数器public Long incrementViewCount(Long productId) { String key PRODUCT_KEY_PREFIX productId; return redisTemplate.opsForHash().increment(key, viewCount, 1); }缓存预热策略PostConstruct public void preloadHotProducts() { ListProduct hotProducts productService.getTop100Products(); hotProducts.forEach(this::cacheProductDetails); }3. 用户会话的String结构缓存方案3.1 会话缓存的特点与选型用户会话数据具有以下特征数据结构简单通常只需存储用户ID和token读写频率极高需要设置精确的过期时间因此opsForValue比opsForHash更合适更简单的命令协议更少的内存开销更快的序列化/反序列化速度3.2 会话服务实现定义会话存储结构Data AllArgsConstructor public class SessionInfo { private Long userId; private String deviceType; private LocalDateTime loginTime; }实现会话服务Service public class SessionService { Autowired private RedisTemplateString, Object redisTemplate; private static final String SESSION_PREFIX session:; public void createSession(String token, SessionInfo session) { String key SESSION_PREFIX token; redisTemplate.opsForValue().set( key, session, 30, // 过期时间 TimeUnit.MINUTES ); } public SessionInfo getSession(String token) { String key SESSION_PREFIX token; return (SessionInfo) redisTemplate.opsForValue().get(key); } public void refreshSession(String token) { String key SESSION_PREFIX token; redisTemplate.expire(key, 30, TimeUnit.MINUTES); } }3.3 安全增强措施并发控制public boolean safeRefreshSession(String token) { String key SESSION_PREFIX token; return redisTemplate.execute( new SessionRefreshCallback(key), 30, TimeUnit.MINUTES); } private static class SessionRefreshCallback implements RedisCallbackBoolean { private final String key; public SessionRefreshCallback(String key) { this.key key; } Override public Boolean doInRedis(RedisConnection connection) { byte[] keyBytes ((RedisSerializerString) redisTemplate.getKeySerializer()).serialize(key); if (connection.exists(keyBytes)) { return connection.expire(keyBytes, 1800); // 30分钟 } return false; } }黑名单处理public void addToBlacklist(String token) { String key blacklist: token; redisTemplate.opsForValue().set( key, , 24, // 黑名单保留时间 TimeUnit.HOURS ); }4. 性能优化与生产实践4.1 基准测试对比通过JMeter对两种结构进行压测100并发操作类型opsForValue QPSopsForHash QPS内存占用差异写入操作12,3459,87615%读取完整数据10,2568,34220%更新单个字段N/A11,298-30%检查存在性14,78913,456基本持平4.2 缓存雪崩预防策略差异化过期时间public void cacheWithRandomExpire(String key, Object value, long baseExpire, TimeUnit unit) { long randomExpire baseExpire ThreadLocalRandom.current().nextLong(baseExpire / 4); redisTemplate.opsForValue().set( key, value, randomExpire, unit ); }多级缓存架构public Product getProductWithMultiCache(Long productId) { // 先查本地缓存 Product product localCache.get(productId); if (product ! null) { return product; } // 再查Redis product productCacheService.getProductDetails(productId); if (product ! null) { localCache.put(productId, product); return product; } // 最后查数据库 product productRepository.findById(productId).orElse(null); if (product ! null) { productCacheService.cacheProductDetails(product); localCache.put(productId, product); } return product; }4.3 监控与告警配置通过Redis命令统计监控缓存健康度# 查看关键指标 redis-cli info stats | grep -E keyspace_hits|keyspace_misses redis-cli info memory | grep used_memory_human # 设置慢查询阈值 redis-cli config set slowlog-log-slower-than 5000Spring Boot集成Prometheus监控Configuration EnableConfigurationProperties(CacheMetricsProperties.class) public class CacheMetricsConfig { Bean public CacheMetricsCollector cacheMetricsCollector( RedisTemplateString, Object redisTemplate) { return new CacheMetricsCollector(redisTemplate); } Bean public MeterBinder cacheHitsMeterBinder( CacheMetricsCollector collector) { return registry - { Gauge.builder(cache.hits, collector::getHitCount) .register(registry); Gauge.builder(cache.misses, collector::getMissCount) .register(registry); }; } }5. 架构演进与扩展思考当系统规模扩大时需要考虑以下进阶方案分布式锁优化public T T executeWithLock(String lockKey, long waitTime, long leaseTime, SupplierT supplier) { String lockName lock: lockKey; try { boolean locked redisTemplate.opsForValue().setIfAbsent( lockName, Thread.currentThread().getName(), leaseTime, TimeUnit.SECONDS ); if (!locked waitTime 0) { long end System.currentTimeMillis() waitTime; while (System.currentTimeMillis() end) { Thread.sleep(100); locked redisTemplate.opsForValue().setIfAbsent( lockName, Thread.currentThread().getName(), leaseTime, TimeUnit.SECONDS ); if (locked) break; } } if (!locked) { throw new RuntimeException(Acquire lock failed); } return supplier.get(); } finally { if (redisTemplate.opsForValue().get(lockName) .equals(Thread.currentThread().getName())) { redisTemplate.delete(lockName); } } }管道化批量操作public ListObject batchGetProducts(ListLong productIds) { return redisTemplate.executePipelined( (RedisCallbackObject) connection - { StringRedisSerializer serializer (StringRedisSerializer) redisTemplate.getKeySerializer(); for (Long id : productIds) { String key product: id; connection.hGetAll(serializer.serialize(key)); } return null; } ); }多级TTL策略public void setWithMultiTtl(String key, Object value, ListLong ttlStages, TimeUnit unit) { redisTemplate.opsForValue().set(key, value); String ttlKey ttl: key; redisTemplate.opsForList().rightPushAll(ttlKey, ttlStages.stream().map(String::valueOf).toArray()); redisTemplate.expire(key, ttlStages.get(0), unit); // 后台任务处理后续TTL taskExecutor.execute(() - { for (int i 1; i ttlStages.size(); i) { try { Thread.sleep(unit.toMillis( ttlStages.get(i-1))); redisTemplate.expire(key, ttlStages.get(i), unit); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } } }); }

相关文章:

Spring Boot + Redis实战:用opsForHash和opsForValue分别搞定商品详情页和用户会话缓存

Spring Boot与Redis深度整合:电商场景下的缓存架构实战 在电商系统的高并发场景中,缓存设计直接决定了用户体验和系统稳定性。商品详情页作为流量最集中的页面之一,其缓存策略需要兼顾数据完整性和访问效率;而用户会话管理则要求快…...

Flink快照保留多久、多少个,设置参数

Flink 快照(Checkpoint)保留数量、保留时间 全套参数 配置我给你最完整、最准确、面试 生产都能用的版本,直接复制即可。一、核心结论(先记这 3 个参数)Flink 控制 快照保留多少个、保留多久,就靠这 3 个…...

你的内容为什么总被说“像别人”?我找到了3个解决办法

做自媒体最怕听到的一句话是什么?不是“写得不好”,而是“你这个跟某某博主好像啊”。我早期就被这样说过好几次,每次心里都很不是滋味。明明是自己想的选题、自己写的文案,怎么就跟别人撞了呢?后来我认真复盘&#xf…...

如何用SteamAutoCrack轻松实现Steam游戏DRM自动破解:完整指南

如何用SteamAutoCrack轻松实现Steam游戏DRM自动破解:完整指南 【免费下载链接】Steam-auto-crack Steam Game Automatic Cracker 项目地址: https://gitcode.com/gh_mirrors/st/Steam-auto-crack SteamAutoCrack是一款革命性的自动化工具,专为合法…...

Steam游戏破解难题:如何用自动化工具轻松绕过DRM限制

Steam游戏破解难题:如何用自动化工具轻松绕过DRM限制 【免费下载链接】Steam-auto-crack Steam Game Automatic Cracker 项目地址: https://gitcode.com/gh_mirrors/st/Steam-auto-crack 你是否曾经遇到过这样的情况:好不容易下载了一款心仪已久的…...

SKILL快速构建你的Java、Python和Node.js开发环境

最新案例动态,请查阅SKILL快速构建你的Java、Python和Node.js开发环境小伙伴们快来进行实操吧! 一、概述 1.1 案例介绍 本案例使用技能一键配置Java、Python、Node.js开发环境,帮助开发者快速搭建高效编程环境,适合初学者和团队…...

SMUDebugTool深度解析:AMD Ryzen处理器底层调试与超频实战指南

SMUDebugTool深度解析:AMD Ryzen处理器底层调试与超频实战指南 【免费下载链接】SMUDebugTool A dedicated tool to help write/read various parameters of Ryzen-based systems, such as manual overclock, SMU, PCI, CPUID, MSR and Power Table. 项目地址: ht…...

ARM SVE指令集与AES加密硬件加速详解

1. ARM SVE指令集与向量处理基础现代处理器架构中,向量处理技术已经成为提升计算性能的关键手段。作为ARMv8架构的重要扩展,可伸缩向量扩展(Scalable Vector Extension, SVE)引入了一种全新的向量编程模型,相比传统的NEON SIMD指令集具有显著…...

DP World Tour欧洲巡回赛携手HCLTech重建官网与球迷应用

DP World Tour(DPWT)欧洲巡回赛与HCLTech签署全球合作协议,旨在借助人工智能技术重新开发其官方网站和球迷应用程序。目前,双方已完成需求调研与范围界定工作,并启动了网站和应用的初步开发冲刺阶段。DPWT首席技术官Mi…...

单GPU运行Mistral NeMo 12B模型的技术解析与优化

1. 单GPU运行Mistral NeMo 12B模型的技术解析在当今生成式AI快速发展的背景下,大型语言模型(Large Language Model, LLM)的应用越来越广泛。然而,大多数高性能LLM需要多GPU甚至GPU集群才能运行,这大大提高了使用门槛和部署成本。NVIDIA与Mist…...

2025届学术党必备的十大降重复率平台推荐

Ai论文网站排名(开题报告、文献综述、降aigc率、降重综合对比) TOP1. 千笔AI TOP2. aipasspaper TOP3. 清北论文 TOP4. 豆包 TOP5. kimi TOP6. deepseek 能够降低AIGC痕迹的关键所在是去减掉生成式人工智能所具有的机械感以及模式化的特征。其一&a…...

Windows 多层嵌套文件夹批量整理:三级文件一键移到二级文件夹

一、问题场景文件夹嵌套结构如下:plaintext一级总文件夹 ├─ 二级文件夹1 │ └─ 三级文件夹(所有文件都在这里) ├─ 二级文件夹2 │ └─ 三级文件夹 ├─ 二级文件夹3 └─ ……(一共80个二级文件夹,每个二级里…...

SoC FPGA在汽车雷达数字信号处理中的优势与应用

1. SoC FPGA在汽车雷达数字处理中的核心优势在汽车雷达系统设计中,数字信号处理(DSP)环节面临着实时性、功耗和成本的多重挑战。传统ASIC方案虽然性能优异,但存在开发周期长、无法升级的致命缺陷。Altera Cyclone V SoC FPGA通过集…...

告别固定类别!用YOLO-World+自定义词汇,5分钟打造你的专属物体检测器

5分钟解锁YOLO-World开放词汇检测:从工业质检到智能零售的零代码实战指南 当传统物体检测模型遇到"螺丝刀型号识别"或"货架商品清点"这类非标准场景时,开发者往往需要经历数据标注、模型训练、部署调试的漫长周期。YOLO-World的开放…...

推荐一下都江堰中央空调、地暖

在现代家居生活中,中央空调、地暖已经成为许多家庭的标配。它不仅能够提供舒适的室内温度,还能提升整体家居的档次。今天,我们就来聊聊都江堰地区的中央空调、地暖选择,重点推荐卡芙曼暖通的产品,并结合一些实际案例和…...

函数式程序员注意!Zig 凭编译时编程、内存管理优势,有望成未来热门语言

表达能力我能在这门语言中多好地表达自己的想法?换句话说,用它来表达程序的业务领域有多容易?这其实是在测试,我在程序中表达想法时会受到多少“噪音”的干扰。这里的“噪音”指的是为了让程序运行而必须编写,但与业务…...

【车辆控制】基于电动车静态PID与动态(动学地平线)自适应巡航控制策略的比较分析附Matlab代码

​✅作者简介:热爱科研的Matlab仿真开发者,擅长毕业设计辅导、数学建模、数据处理、建模仿真、程序设计、完整代码获取、论文复现及科研仿真。🍎 往期回顾关注个人主页:Matlab科研工作室👇 关注我领取海量matlab电子书…...

国标GB28181之后,视频监控EasyCVR的下一个“统一战场”在哪里?

2011年,GB28181的发布,结束了中国视频监控"七国八制"的混乱局面。历经2016版、2022版两次重大迭代,这一国标已成长为安防行业不可或缺的技术基石。但对于专业集成商而言,一个更深层的问题浮出水面:国标之后&…...

从Hal库到标准库:手把手教你将机智云自动代码移植到STM32F103(附完整工程)

从Hal库到标准库:STM32F103与机智云物联网开发实战指南 在物联网设备开发中,快速实现硬件与云平台的对接是提升开发效率的关键。对于使用STM32系列MCU的开发者而言,机智云平台提供的自动代码生成工具能显著缩短开发周期,但生成的基…...

深度学习图像描述生成技术解析与应用实践

1. 深度学习图像描述生成模型入门指南 在计算机视觉与自然语言处理的交叉领域,图像描述生成(Image Captioning)技术正逐渐改变人机交互的方式。想象一下,当视障人士的手机能够准确描述周围环境,当电商平台可以自动为海…...

ARM ST4指令解析:SIMD向量存储优化与实践

1. ARM ST4指令深度解析:SIMD向量存储的底层实现在ARMv8/ARMv9架构中,SIMD(单指令多数据)技术通过并行处理大幅提升计算效率,是现代CPU设计的核心特性。作为AdvSIMD扩展的重要组成部分,ST4指令专为高效存储…...

养虾成功!OpenClaw 接入微信全记录(附配置模型关键步骤)

微信发布了Clawbot插件,意味着可以将OpenClaw接入生态啦。不需要企业资质,也不用搞复杂的开发,只需四步就能拥有一个24小时在线的AI私人管家。本文将一步步带你完成OpenClaw接入微信的全流程,帮你轻松开启AI助手的智能对话体验。 …...

AI助手成本监控仪表盘:本地化Token用量与费用可视化方案

1. 项目概述:一个轻量级的AI助手成本监控仪表盘最近在折腾各种AI助手工具,像Cursor、Claude这些,用起来是真爽,但月底一看账单,心里就有点发毛。特别是当你开了多个项目,让AI助手帮你写代码、分析文档、甚至…...

定氢探头精准把控氢含量——唐山大方汇中仪表

氢含量是影响高品质钢、特殊钢种性能的关键指标,氢脆、气孔等缺陷直接降低钢材使用寿命。定氢探头作为冶金行业氢含量检测专用元件,专为高端特种钢冶炼量身打造,是生产轨道交通钢、钎钢钎具等精品钢材的核心器件。 唐山大方汇中仪表自主研发…...

使用 taotoken cli 工具一键配置团队开发环境与模型密钥

使用 Taotoken CLI 工具一键配置团队开发环境与模型密钥 1. 安装 Taotoken CLI Taotoken CLI 工具提供两种安装方式,适用于不同场景: 全局安装(适合长期使用): npm install -g taotoken/taotoken安装后可直接在终端运…...

TSX07311628扩展模块

TSX07311628 是施耐德电气 Modicon Nano 系列中的一款紧凑型可编程逻辑控制器模块,主要用于小型自动化项目的逻辑控制与设备驱动。以下是该模块的15条主要产品特点:中间15条特点:属于施耐德 Modicon Nano 系列紧凑型可编程控制器集成 16 个输…...

深入AutoSar CAN通信栈:图解CAN IF模块如何桥接CAN Driver与上层

深入解析AutoSar CAN通信栈:CAN IF模块的架构设计与数据流转 在汽车电子系统开发中,CAN总线作为最常用的车载网络协议,其通信栈的设计直接影响着整车电子架构的可靠性和性能。AutoSar标准中的CAN通信栈作为基础软件层(BSW&#xf…...

开源对话大模型MOSS:从架构解析到微调部署实战指南

1. 项目概述:一个开源的对话式大语言模型最近在开源社区里,usemoss/moss这个项目引起了我的注意。简单来说,这是一个由复旦大学自然语言处理实验室(FudanNLP)团队开发并开源的中英双语对话大语言模型。它的名字“MOSS”…...

Windows Internals 读书笔记 10.5.8:ETW 安全机制,不只是记录日志,更是权限与证据链管理

🔥个人主页:杨利杰YJlio❄️个人专栏:《Sysinternals实战教程》《Windows PowerShell 实战》《WINDOWS教程》《IOS教程》《微信助手》《锤子助手》 《Python》 《Kali Linux》 《那些年未解决的Windows疑难杂症》🌟 让复杂的事情更…...

【js】浏览器滚动条优化组件OverlayScrollbars

前言在前端,滚动条作为一个长期被吐槽却又不得不忍受的存在,几乎出现在每个页面里,却又几乎无法优雅地控制。而且当你的开发系统是mac(隐藏滚动条模式),而生产环境则是古老的win……就出现了完全没有”预料…...