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

通过Redis增减库存避坑

问题
先执行get获取值,判断符合条件再执行incr、decr操作。在临界缓存失效的情况下,会默认赋值当前key为永不过期的0,再执行加减法,导致程序异常。

推荐解决方案
1、限制接口频率:先incr,执行后值为1,说明是第一次执行,需要额外设置过期时间,再判断是否超过当前接口频率限制(注意上述步骤不可调换顺序)

2、使用lua脚本完整提交一次操作,脚本中的key可以保证一致。以加减库存为例,先查询key存在的情况下,再进行库存变更,如果不存在无需处理,等待下次缓存加载即为最新的值


问题描述

场景1:我们缓存了一个商品的库存,过期时间为5分钟,根据用户的购买和取消执行 incr、decr 操作。代码通常会这样来编写:

		// 库存存在则加一if(redisService.get(prefix, key, Integer.class) != null){redisService.incr(prefix, key);}

场景2:对访问频次进行限流,我们可以通过redis简单实现:

        // 首先获取当前访问频次Integer count = redisService.get(prefix, key, Integer.class);// 如果频次为空,则设置访问次数为1if (count == null) {redisService.set(prefix, key, 1);} else if (count < checkFrequencyCount) {// 如果频次小于限制,则设置访问次数加1redisService.incr(prefix, key);} else {// 如果频次超过限制,则限流throw new AppException("访问频次过高,请稍候再试");}

两种场景编码看似都没有问题,但实际运行中却发现redis中有一些key变成了永不过期的key,而且值不正确。

原因是: 因为redis的incr操作,当key不存在时, 会生成这个key并将值初始化为0, 并且默认设置key的有效时间为永久。


解决方案

1.优化Java代码,例如场景2。不论这个key是否存在都先加一,然后判断其过期时间是否为永不过期,如果是永不过期则说明是新生成的key,给它设置过期时间即可,如果非永不过期则无需操作。最后再判断一下是否值已经大于访问频次了,是则限流。

		long count = redisService.incr(prefix, key);// 判断必须放在后面,否则key没有过期时间永远无法清除long expire = redisService.ttl(prefix, key);if (expire == -1) {redisService.setExpire(prefix, key, accessExpireSecond);}if (count > checkFrequencyCount) {throw new AppException("访问频次过高,请稍候再试");}

2.使用lua脚本执行,保证原子性。

脚本updateStore.lua

--- 获取key
local key = KEYS[1]
--- 获取参数:incr、decr
local action = ARGV[1]
--- 如果key存在,再执行增加或减少的操作
if redis.call('exists', key) == 1 
then redis.call(action, key)return true
end 
return false

配置LuaConfiguration.java

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.scripting.support.ResourceScriptSource;@Configuration
public class LuaConfiguration {@Bean(name = "update")public DefaultRedisScript<Boolean> redisScript() {DefaultRedisScript<Boolean> redisScript = new DefaultRedisScript<>();redisScript.setScriptSource(new ResourceScriptSource(new ClassPathResource("luascript/updateStore.lua")));redisScript.setResultType(Boolean.class);return redisScript;}
}

使用方法:

    @Resource(name = "update")private DefaultRedisScript<Boolean> redisScript;@Resourceprivate StringRedisTemplate stringRedisTemplate;// 执行脚本并传参Boolean result = stringRedisTemplate.execute(redisScript, Arrays.asList(stockPrefix.getPrefix() + key), "incr");

相关文章:

通过Redis增减库存避坑

问题&#xff1a; 先执行get获取值&#xff0c;判断符合条件再执行incr、decr操作。在临界缓存失效的情况下&#xff0c;会默认赋值当前key为永不过期的0&#xff0c;再执行加减法&#xff0c;导致程序异常。 推荐解决方案&#xff1a; 1、限制接口频率&#xff1a;先incr&…...

Windows系统搭建Elasticsearch引擎结合内网穿透实现远程连接查询数据

文章目录 系统环境1. Windows 安装Elasticsearch2. 本地访问Elasticsearch3. Windows 安装 Cpolar4. 创建Elasticsearch公网访问地址5. 远程访问Elasticsearch6. 设置固定二级子域名 Elasticsearch是一个基于Lucene库的分布式搜索和分析引擎&#xff0c;它提供了一个分布式、多…...

Java爬虫使用JSoup获取静态资源图片

import org.jsoup.Connection; import org.jsoup.Jsoup; import org.jsoup.nodes.Document; import org.jsoup.nodes.Element; import org.jsoup.select.Elements; import java.io.FileOutputStream;/*** 获取静态图片*/public class ImageDownloader {public static void main…...

LeetCode 2433.找出前缀异或的原始数组

给你一个长度为 n 的 整数 数组 pref 。找出并返回满足下述条件且长度为 n 的数组 arr &#xff1a; pref[i] arr[0] ^ arr[1] ^ … ^ arr[i]. 注意 ^ 表示 按位异或&#xff08;bitwise-xor&#xff09;运算。 可以证明答案是 唯一 的。 示例 1&#xff1a; 输入&#xf…...

C++面试:系统网络性能评估与优化

系统网络性能评估与优化是指对计算机系统中的网络部分进行评估分析&#xff0c;并采取一系列措施来提升网络性能的能力。在面试中&#xff0c;涉及这一主题的问题可能会围绕以下几个方面展开。 网络性能评估 基于网络延迟、带宽、吞吐量等指标对网络性能进行评估。使用工具&a…...

Java适配器模式 - 灵活应对不匹配的接口

Java适配器模式 - 灵活应对不匹配的接口 引言&#xff1a; 在软件开发中&#xff0c;我们经常遇到不同系统、库或框架之间的接口不兼容问题。为了解决这些问题&#xff0c;我们可以使用适配器模式。适配器模式是一种结构型设计模式&#xff0c;它允许不兼容的接口之间进行协作…...

[ai笔记12] chatGPT技术体系梳理+本质探寻

欢迎来到文思源想的ai空间&#xff0c;这是技术老兵重学ai以及成长思考的第12篇分享&#xff01; 这周时间看了两本书&#xff0c;一本是大神斯蒂芬沃尔弗拉姆学的《这就是ChatGPT》,另外一本则是腾讯云生态解决方案高级架构师宋立恒所写的《AI制胜机器学习极简入门》&#xf…...

Elasticsearch:使用 ELSER v2 进行语义搜索

在我之前的文章 “Elasticsearch&#xff1a;使用 ELSER 进行语义搜索”&#xff0c;我们展示了如何使用 ELESR v1 来进行语义搜索。在使用 ELSER 之前&#xff0c;我们必须注意的是&#xff1a; 重要&#xff1a;虽然 ELSER V2 已正式发布&#xff0c;但 ELSER V1 仍处于 [预览…...

智慧农业之智能物流

智慧物流属于农业生产环节中的重要节点,上游为农业生产环节,下游为销售与商贸环节,因此,通过联通生产与销售环节,通过合理调配物流过程,可以实现对于农产品的快速运输与销售,减少中间环节中的无效损耗,从而实现增收节支,实实在在地解决了农产品利润偏低的问题。 生产…...

Redis主从、哨兵、Redis Cluster集群架构

Redis主从、哨兵、Redis Cluster集群架构 Redis主从架构 Redis主从架构搭建 主从搭建的问题 如果同步数据失败&#xff0c;查看log日志报错无法连接&#xff0c;检查是否端口未开放出现”Error reply to PING from master:...“日志&#xff0c;修改参数protected-mode no …...

Javascript 运算符、流程控制语句和数组

【三】运算符 【1】算数运算符 &#xff08;1&#xff09;分类 加减乘除&#xff1a;*/取余&#xff1a;%和python不一样的点&#xff1a;没有取整// &#xff08;2&#xff09;特殊的点 只要NaN参与运算得到的结果也是NaNnull转换成0&#xff0c;undefined转换成NaN 【2…...

电机驱动死区时间

电机驱动死区时间 电机驱动死区时间死区时间&#xff08;Dead Time&#xff09;自己话补充说明 电机驱动死区时间 电机驱动死区时间一般在几纳秒到几微秒之间&#xff0c;具体长度取决于所使用的电子器件。 一、什么是电机驱动死区时间&#xff1f; 电机驱动死区时间指的是在电…...

图像的压缩感知的MATLAB实现(第3种方案)

前面介绍了两种不同的压缩感知实现&#xff1a; 图像压缩感知的MATLAB实现&#xff08;OMP&#xff09; 压缩感知的图像仿真&#xff08;MATLAB源代码&#xff09; 上述两种方法还存在着“速度慢、精度低”等不足。 本篇介绍一种新的方法。 压缩感知&#xff08;Compressed S…...

高温应用中GaN HEMT大信号建模的ASM-HEMT

来源&#xff1a;An ASM-HEMT for Large-Signal Modeling of GaN HEMTs in High-Temperature Applications&#xff08;JEDS 23年&#xff09; 摘要 本文报道了一种用于模拟高温环境下氮化镓高电子迁移率晶体管&#xff08;GaN HEMT&#xff09;的温度依赖性ASM-HEMT模型。我…...

文件上传---->生僻字解析漏洞

现在的现实生活中&#xff0c;存在文件上传的点&#xff0c;基本上都是白名单判断&#xff08;很少黑名单了&#xff09; 对于白名单&#xff0c;我们有截断&#xff0c;图片马&#xff0c;二次渲染&#xff0c;服务器解析漏洞这些&#xff0c;于是今天我就来补充一种在upload…...

Ubuntu中Python3找不到_sqlite3模块

今天跑一个代码&#xff0c;出现了一个找不到sqlite3模块的错误&#xff0c;错误如下: from _sqlite3 import * ModuleNotFoundError: No module named _sqlite3 网上查资料说&#xff0c;因为python3没有自带sqlite3相关方面的支持&#xff0c;要自己先安装然后再重新编译Py…...

HarmonyOS4.0系统性深入开发37 改善布局性能

改善布局性能 Flex为采用弹性布局的容器。容器内部的所有子元素&#xff0c;会自动参与弹性布局。子元素默认沿主轴排列&#xff0c;子元素在主轴方向的尺寸称为主轴尺寸。 在单行布局场景下&#xff0c;容器里子组件的主轴尺寸长度总和可能存在不等于容器主轴尺寸长度的情况…...

Internet协议

文章目录 Internet协议网络层协议IPV4协议IP地址&#xff1a;IPv4数据报格式IP数据报的封装和分片 Internet路由协议路由信息协议RIP开放最短路径优先协议OSPF外部网关协议BGP组播协议PIM和MOSPF ARP和RARPARP协议&#xff1a;RARP协议&#xff1a; Internet控制报文协议ICMPIP…...

深度学习基础(一)神经网络基本原理

之前的章节我们初步介绍了机器学习相关基础知识&#xff0c;目录如下&#xff1a; 机器学习基础&#xff08;一&#xff09;理解机器学习的本质-CSDN博客 机器学习基础&#xff08;二&#xff09;监督与非监督学习-CSDN博客 机器学习基础&#xff08;四&#xff09;非监督学…...

2024年2月22日 - mis

rootyy3568-alip:/sys# ls /sys/class/gpio/gpio* -F /sys/class/gpio/gpio114 /sys/class/gpio/gpiochip511 /sys/class/gpio/gpiochip0 /sys/class/gpio/gpiochip64 /sys/class/gpio/gpiochip128 /sys/class/gpio/gpiochip96 /sys/class/gpio/gpiochip32符号表示该文…...

多云管理“拦路虎”:深入解析网络互联、身份同步与成本可视化的技术复杂度​

一、引言&#xff1a;多云环境的技术复杂性本质​​ 企业采用多云策略已从技术选型升维至生存刚需。当业务系统分散部署在多个云平台时&#xff0c;​​基础设施的技术债呈现指数级积累​​。网络连接、身份认证、成本管理这三大核心挑战相互嵌套&#xff1a;跨云网络构建数据…...

React Native在HarmonyOS 5.0阅读类应用开发中的实践

一、技术选型背景 随着HarmonyOS 5.0对Web兼容层的增强&#xff0c;React Native作为跨平台框架可通过重新编译ArkTS组件实现85%以上的代码复用率。阅读类应用具有UI复杂度低、数据流清晰的特点。 二、核心实现方案 1. 环境配置 &#xff08;1&#xff09;使用React Native…...

【2025年】解决Burpsuite抓不到https包的问题

环境&#xff1a;windows11 burpsuite:2025.5 在抓取https网站时&#xff0c;burpsuite抓取不到https数据包&#xff0c;只显示&#xff1a; 解决该问题只需如下三个步骤&#xff1a; 1、浏览器中访问 http://burp 2、下载 CA certificate 证书 3、在设置--隐私与安全--…...

[Java恶补day16] 238.除自身以外数组的乘积

给你一个整数数组 nums&#xff0c;返回 数组 answer &#xff0c;其中 answer[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积 。 题目数据 保证 数组 nums之中任意元素的全部前缀元素和后缀的乘积都在 32 位 整数范围内。 请 不要使用除法&#xff0c;且在 O(n) 时间复杂度…...

是否存在路径(FIFOBB算法)

题目描述 一个具有 n 个顶点e条边的无向图&#xff0c;该图顶点的编号依次为0到n-1且不存在顶点与自身相连的边。请使用FIFOBB算法编写程序&#xff0c;确定是否存在从顶点 source到顶点 destination的路径。 输入 第一行两个整数&#xff0c;分别表示n 和 e 的值&#xff08;1…...

优选算法第十二讲:队列 + 宽搜 优先级队列

优选算法第十二讲&#xff1a;队列 宽搜 && 优先级队列 1.N叉树的层序遍历2.二叉树的锯齿型层序遍历3.二叉树最大宽度4.在每个树行中找最大值5.优先级队列 -- 最后一块石头的重量6.数据流中的第K大元素7.前K个高频单词8.数据流的中位数 1.N叉树的层序遍历 2.二叉树的锯…...

Mysql中select查询语句的执行过程

目录 1、介绍 1.1、组件介绍 1.2、Sql执行顺序 2、执行流程 2.1. 连接与认证 2.2. 查询缓存 2.3. 语法解析&#xff08;Parser&#xff09; 2.4、执行sql 1. 预处理&#xff08;Preprocessor&#xff09; 2. 查询优化器&#xff08;Optimizer&#xff09; 3. 执行器…...

Java毕业设计:WML信息查询与后端信息发布系统开发

JAVAWML信息查询与后端信息发布系统实现 一、系统概述 本系统基于Java和WML(无线标记语言)技术开发&#xff0c;实现了移动设备上的信息查询与后端信息发布功能。系统采用B/S架构&#xff0c;服务器端使用Java Servlet处理请求&#xff0c;数据库采用MySQL存储信息&#xff0…...

AI语音助手的Python实现

引言 语音助手(如小爱同学、Siri)通过语音识别、自然语言处理(NLP)和语音合成技术,为用户提供直观、高效的交互体验。随着人工智能的普及,Python开发者可以利用开源库和AI模型,快速构建自定义语音助手。本文由浅入深,详细介绍如何使用Python开发AI语音助手,涵盖基础功…...

stm32wle5 lpuart DMA数据不接收

配置波特率9600时&#xff0c;需要使用外部低速晶振...