在电商系统中,商品详情页是一个典型的高频访问场景。当用户请求某个商品的详情时,系统会优先从缓存中获取数据。如果缓存中没有该商品的详情,系统会去数据库查询并更新缓存。然而,如果某个热门商品的缓存失效,大量请求会同时查询数据库,导致数据库压力骤增,这就是缓存击穿问题。
以下是一个结合布隆过滤器防止缓存击穿的Java伪代码实现案例:
场景描述
商品详情查询:用户通过商品ID查询商品详情。
缓存层:使用Redis作为缓存,存储商品详情。
布隆过滤器:使用RedisBloom模块实现布隆过滤器,存储所有可能被查询的商品ID。
数据库层:存储商品详情的数据库。
实现思路
初始化布隆过滤器:
在系统启动时,将数据库中所有商品的ID插入到布隆过滤器中。
查询流程:
当用户请求商品详情时,先通过布隆过滤器判断该商品ID是否存在。
如果布隆过滤器判断不存在,则直接返回“商品不存在”。
如果布隆过滤器判断可能存在,则去缓存中查询。
如果缓存中有数据,则直接返回缓存结果。
如果缓存中没有数据,则去数据库查询,并将结果放入缓存。
Java伪代码实现

import io.lettuce.core.RedisClient;
import io.lettuce.core.api.sync.RedisCommands;
import io.lettuce.core.bloom.BloomOptions;
import io.lettuce.core.bloom.RedisBloomCommands;import java.util.concurrent.locks.ReentrantLock;public class ProductService {// Redis客户端private RedisClient redisClient;private RedisCommands<String, String> syncCommands;private RedisBloomCommands<String, String> bloomCommands;// 数据库客户端private DatabaseClient databaseClient;// 布隆过滤器的Keyprivate static final String BLOOM_FILTER_KEY = "product:bloomfilter";// 缓存Key前缀private static final String CACHE_KEY_PREFIX = "product:cache:";// 锁,用于防止缓存击穿时的并发问题private ReentrantLock lock = new ReentrantLock();public ProductService(RedisClient redisClient, DatabaseClient databaseClient) {this.redisClient = redisClient;this.syncCommands = redisClient.connect().sync();this.bloomCommands = redisClient.connect().sync();this.databaseClient = databaseClient;}// 初始化布隆过滤器public void initBloomFilter() {// 获取所有商品IDList<String> productIds = databaseClient.getAllProductIds();// 初始化布隆过滤器bloomCommands.bfCreate(BLOOM_FILTER_KEY, BloomOptions.defaults(), productIds.size());// 将所有商品ID插入布隆过滤器for (String productId : productIds) {bloomCommands.bfAdd(BLOOM_FILTER_KEY, productId);}}// 查询商品详情public Product getProductDetails(String productId) {// 1. 使用布隆过滤器判断商品ID是否存在boolean exists = bloomCommands.bfExists(BLOOM_FILTER_KEY, productId);if (!exists) {// 如果布隆过滤器判断不存在,直接返回商品不存在return null;}// 2. 从缓存中查询商品详情String cacheKey = CACHE_KEY_PREFIX + productId;String productDetails = syncCommands.get(cacheKey);if (productDetails != null) {// 如果缓存中有数据,直接返回return new Product(productDetails);}// 3. 缓存中没有数据,加锁防止缓存击穿lock.lock();try {// 再次检查缓存,防止并发问题productDetails = syncCommands.get(cacheKey);if (productDetails != null) {return new Product(productDetails);}// 4. 查询数据库Product product = databaseClient.getProductById(productId);if (product != null) {// 将查询结果放入缓存syncCommands.set(cacheKey, product.toJson());}return product;} finally {lock.unlock();}}
}// 数据库客户端
class DatabaseClient {// 获取所有商品IDpublic List<String> getAllProductIds() {// 查询数据库,返回所有商品IDreturn database.query("SELECT id FROM products");}// 根据商品ID查询商品详情public Product getProductById(String productId) {// 查询数据库,返回商品详情return database.query("SELECT * FROM products WHERE id = ?", productId);}
}// 商品类
class Product {private String id;private String name;private double price;public Product(String details) {// 从JSON字符串解析商品详情this.id = parseId(details);this.name = parseName(details);this.price = parsePrice(details);}public String toJson() {// 将商品详情转换为JSON字符串return "{\"id\":\"" + id + "\",\"name\":\"" + name + "\",\"price\":" + price + "}";}
}

代码说明
布隆过滤器初始化:
在系统启动时,调用initBloomFilter方法,将所有商品ID插入到布隆过滤器中。
查询流程:
使用布隆过滤器判断商品ID是否存在。
如果布隆过滤器判断不存在,则直接返回null。
如果布隆过滤器判断可能存在,则去缓存中查询。
如果缓存中没有数据,则加锁并查询数据库,将结果放入缓存。
锁机制:
使用ReentrantLock防止缓存击穿时的并发问题。
在加锁后再次检查缓存,确保只有一个线程去查询数据库。
优点
减少无效查询:布隆过滤器可以快速判断商品ID是否存在,减少对不存在商品的查询。
减轻数据库压力:即使缓存失效,也能通过布隆过滤器减少对数据库的直接查询。
缺点
布隆过滤器误判:虽然误判率可以通过调整参数降低,但无法完全避免。
锁机制的开销:在高并发场景下,锁可能会成为性能瓶颈。
通过以上实现,电商系统可以在商品详情查询场景中有效缓解缓存击穿问题,同时结合布隆过滤器减少对数据库的无效查询。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/bicheng/91379.shtml
繁体地址,请注明出处:http://hk.pswp.cn/bicheng/91379.shtml
英文地址,请注明出处:http://en.pswp.cn/bicheng/91379.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

1+1>2!特征融合如何让目标检测更懂 “场景”?

来gongzhonghao【图灵学术计算机论文辅导】&#xff0c;快速拿捏更多计算机SCI/CCF发文资讯&#xff5e;在多模态大模型&#xff08;MLLM&#xff09;时代&#xff0c;特征融合与目标检测的研究方向正变得愈发关键。从红外与可见光图像的融合&#xff0c;到语音活动检测中的特征…

详解赛灵思SRIO IP并提供一种FIFO封装SRIO的收发控制器仿真验证

概述RapidIO标准定义为三层&#xff1a;逻辑层、传输层、物理层。逻辑层&#xff1a;定义总体协议和包格式&#xff0c;包含设备发起/完成事务的必要信息。传输层&#xff1a;提供包传输的路由信息&#xff08;对顶层不可见&#xff09;。物理层&#xff1a;描述设备级接口细节…

深度学习:简介与任务分类总览

一、什么是深度学习&#xff1f;1.1 深度学习的定义深度学习&#xff08;Deep Learning&#xff09;是机器学习的一种特殊形式&#xff0c;它依赖于具有多层结构的神经网络自动从数据中学习特征并完成任务&#xff0c;如图像识别&#xff0c;语音识别&#xff0c;自然语言处理等…

MSPM0开发学习笔记:二维云台画图(2025电赛 附源代码及引脚配置)

前言 今年的电赛&#xff08;2025&#xff09;&#xff0c;很多题都与云台相关&#xff0c;因此为备战电赛&#xff0c;博主这边也是准备了一个由两个42步进电机驱动的云台并提前进行调试&#xff0c;避免赛题出来之后手忙脚乱的&#xff0c;这边的两个42步进电机采用同一个驱…

借助 Wisdom SSH 的 AI 助手构建 Linux 开发环境

借助Wisdom SSH的AI助手构建Linux开发环境 在Linux系统的开发场景中&#xff0c;快速、准确地搭建开发环境至关重要。Wisdom SSH凭借其强大的AI助手&#xff0c;能极大简化这一过程&#xff0c;其官网为ssh.wisdomheart.cn。以下以在Ubuntu 22.04服务器上构建Python开发环境&am…

Python 程序设计讲义(44):组合数据类型——集合类型:创建集合

Python 程序设计讲义&#xff08;44&#xff09;&#xff1a;组合数据类型——集合类型&#xff1a;创建集合 目录Python 程序设计讲义&#xff08;44&#xff09;&#xff1a;组合数据类型——集合类型&#xff1a;创建集合一、集合的特征二、创建集合&#xff1a;使用set()函…

10 - 大语言模型 —Transformer 搭骨架,BERT 装 “双筒镜”|解密双向理解的核心

目录 1、为什么 BERT 能 “懂” 语言&#xff1f;先看它的 “出身” 2、核心逻辑 2.1、“自学阶段”—— 预训练&#xff0c;像婴儿学说话一样积累语感 2.1.1、简述 2.1.2、核心本事&#xff1a;“双向注意力”&#xff0c;像人一样 “聚焦重点” 2.2、“专项复习”—— …

【Spring Boot 快速入门】四、MyBatis

目录MyBatis&#xff08;一&#xff09;入门简介MyBatis 入门LombokMyBatis 基础操作数据准备删除预编译新增更新查询XML 映射文件MyBatis&#xff08;一&#xff09;入门 简介 MyBatis 是一款 优秀的持久层框架&#xff0c;它支持 自定义 SQL、存储过程以及高级映射&#xf…

Spring IOC 基于Cglib实现含构造函数的类实例化策略

作者&#xff1a;小凯 分享、让自己和他人都能有所收获&#xff01; 一、前言 技术成长&#xff0c;是对场景设计细节不断的雕刻&#xff01; 你觉得自己的技术什么时候得到了快速的提高&#xff0c;是CRUD写的多了以后吗&#xff1f;想都不要想&#xff0c;绝对不可能&#xf…

composer 常用命令

### 设置镜像源全局设置composer config -g repo.packagist composer https://mirrors.aliyun.com/composer/当个项目设置composer config repo.packagist composer https://mirrors.aliyun.com/composer/恢复官方源composer config -g --unset repos.packagist### 常用源阿里云…

【python】Python爬虫入门教程:使用requests库

Python爬虫入门教程&#xff1a;使用requests库 爬虫是数据获取的重要手段&#xff0c;下面我将通过一个完整的示例&#xff0c;教你如何使用Python的requests库编写一个简单的爬虫。我们将以爬取豆瓣电影Top250为例。 【python】网络爬虫教程 - 教你用python爬取豆瓣电影 Top…

OpenCV图像缩放:resize

图像缩放是图像处理中的基础操作之一。无论是图像预处理、数据增强还是图像金字塔构建&#xff0c;cv::resize 都是我们最常用的函数之一。但你是否注意到&#xff0c;在 OpenCV 中同时还存在一个名为 cv::Mat::resize 的方法&#xff1f;这两个函数虽然名字类似&#xff0c;但…

汽车、航空航天、适用工业虚拟装配解决方案

一、现状在制造业数字化转型浪潮中&#xff0c;传统装配过程仍面临诸多挑战&#xff1a;物理样机试错成本高、装配周期冗长、工艺优化依赖经验、跨部门协作效率低下……如何打破“试错-返工”的恶性循环&#xff1f;目前总装工艺通过DELMIA、NX、Creo等工程软件进行工艺装配验证…

页面跳转和前端路由的区别

传统方式&#xff1a;通过改变浏览器地址栏的 URL 来实现window.location.href /new-page<a href"/new-page">跳转到新页面</a>会导致整个页面重新加载会触发浏览器向服务器发送新的请求页面状态不会保留&#xff0c;所有资源重新加载可以避免新上线的内…

C/C++核心知识点详解

C/C核心知识点详解 1. 变量的声明与定义&#xff1a;内存分配的本质区别 核心概念 在C/C中&#xff0c;变量的声明和定义是两个完全不同的概念&#xff1a; 声明&#xff08;Declaration&#xff09;&#xff1a;告诉编译器变量的名称和类型&#xff0c;但不分配内存空间定义&a…

物联网发展:从概念到应用的演变历程

物联网的发展历程是一部技术革新与社会需求共同驱动的进化史&#xff0c;其演变可划分为概念萌芽、技术积累、应用拓展和智能融合四个阶段&#xff0c;每个阶段均以关键技术突破或社会需求变革为标志&#xff0c;最终形成万物互联的智能生态。以下是具体演变历程&#xff1a;一…

一个人开发一个App(数据库)

后端要保存数据&#xff0c;我还是选择了关系型数据库Mysql, 因为其它的不熟悉。 flutter端这次我选择的是ObjectBox&#xff0c;以前都是直接用的sqlite3&#xff0c;看对比ObjectBox效率比sqlite3高许多&#xff0c;这次前端为了用户体验&#xff0c;我需要缓存数据&#xff…

天铭科技×蓝卓 | “1+2+N”打造AI驱动的汽车零部件行业智能工厂

7月24日&#xff0c;杭州天铭科技股份有限公司&#xff08;简称 “天铭科技”&#xff09;与蓝卓数字科技有限公司&#xff08;简称 “蓝卓”&#xff09;签订全面战略合作协议。天铭科技董事长张松、副总经理艾鸿冰&#xff0c;蓝卓副董事长谭彰等领导出席签约仪式&#xff0c…

技术复盘报告:Vue表格中多行文本字段数据保存丢失问题

1. 问题背景 在一个基于 Vue 2.0 和 ElementUI 的复杂数据维护页面中&#xff0c;用户报告了一个偶发但严重的问题&#xff1a;在表格中编辑一个多行文本&#xff08;textarea&#xff09;字段时&#xff0c;输入的内容有时会在点击“保存”后丢失。 具体表现&#xff1a; 前端…

#C语言——学习攻略:深挖指针路线(四)--字符指针变量,数组指针变量,二维数组传参的本质,函数指针变量,函数指针数组

&#x1f31f;菜鸟主页&#xff1a;晨非辰的主页 &#x1f440;学习专栏&#xff1a;《C语言学习》 &#x1f4aa;学习阶段&#xff1a;C语言方向初学者 ⏳名言欣赏&#xff1a;"暴力解法是上帝给的&#xff0c;优化解法是魔鬼教的。" 目录 1. 字符指针变量 1.1 使…