使用Redis+Lua通过原子减解决超卖问题[示例]
作者:小教学发布时间:2023-09-19分类:程序开发学习浏览:78
导读:系列文章目录一、SpringBoot连接MYSQL数据库实例[tk.mybatis连接MYSQL数据库]二、SpringBoot连接Redis与Redisson[代码]三、Spri...
系列文章目录
一、SpringBoot连接MYSQL数据库实例[tk.mybatis连接MYSQL数据库]
二、SpringBoot连接Redis与Redisson[代码]
三、SpringBoot整合WebSocket[代码]
四、使用Redis+Lua通过原子减解决超卖问题[示例]
五、SpringBoot整合ElasticSearch[代码示例]
文章目录
- 系列文章目录
- 前言
- 一、准备工作
- 二、不使用Lua
- 三、使用Lua
前言
超卖,即在并发的情况下,所售商品数量大于商品的库存数量.在并发量大的情况下,用户请求同时到达,对数据库进行操作,在没有采取相应的处理的情况时从而导致出现超卖现象.
一、准备工作
在redis中放入十件商品
二、不使用Lua
使用20个线程抢商品
public void test () {
ExecutorService service = Executors.newFixedThreadPool(20);
for (int i = 0; i < 20; i++) {
int finalI = i;
service.execute(new Runnable() {
@Override
public void run() {
if (Integer.parseInt(String.valueOf(redisUtils.get("test"))) > 0) {
int execute = Integer.parseInt(String.valueOf(redisUtils.decr("test", 1)));
if (execute != 0) {
log.info("线程" + finalI + "抢到了商品!!!");
} else {
log.info("线程" + finalI + "未抢到商品");
}
} else {
log.info("商品数量不足");
}
}
});
}
}
运行代码发现已经超出了十个人抢到了商品.
此时redis的存值已经变为了负数,出现了超卖的情况.
三、使用Lua
public void test_lua () {
StringBuilder sb = new StringBuilder();
sb.append("if (redis.call('exists', KEYS[1]) == 1) then"); // 判断key是否存在
sb.append(" local stock = tonumber(redis.call('get', KEYS[1]));"); // 获取锁
sb.append(" if (stock == -1) then");
sb.append(" return 1;");
sb.append(" end;");
sb.append(" if (stock > 0) then");
sb.append(" redis.call('decrby', KEYS[1], 1);"); // 商品数量减1
sb.append(" return stock;");
sb.append(" end;");
sb.append(" return 0;");
sb.append("end;");
sb.append("return -1;");
String STOCK_LUA = sb.toString();
DefaultRedisScript<Long> objectDefaultRedisScript = new DefaultRedisScript<>();
objectDefaultRedisScript.setScriptText(STOCK_LUA);
objectDefaultRedisScript.setResultType(Long.class);
ArrayList<String> keys = new ArrayList<>(); // 脚本中的KEYS参数
keys.add("test");
ExecutorService service = Executors.newFixedThreadPool(20);
for (int i = 0; i < 20; i++) {
int finalI = i;
service.execute(new Runnable() {
@Override
public void run() {
int execute = Integer.parseInt(redisTemplate.execute(objectDefaultRedisScript, keys).toString());
if (execute != 0) {
log.info("线程" + finalI + "抢到了商品!!!");
} else {
log.info("线程" + finalI + "未抢到商品");
}
}
});
}
}
依然使用20个线程抢商品,运行代码只有10个线程抢到了商品
此时Redis中的存值为%0
标签:的博客
- 上一篇:网络安全(黑客)自学
- 下一篇:C语言指针进阶(2)
- 程序开发学习排行
-
- 1鸿蒙HarmonyOS:Web组件网页白屏检测
- 2HTTPS协议是安全传输,为啥还要再加密?
- 3HarmonyOS鸿蒙应用开发——数据持久化Preferences
- 4记解决MaterialButton背景颜色与设置值不同
- 5鸿蒙HarmonyOS实战-ArkUI组件(RelativeContainer)
- 6鸿蒙HarmonyOS实战-ArkUI组件(Stack)
- 7[Android][NDK][Cmake]一文搞懂Android项目中的Cmake
- 8鸿蒙HarmonyOS实战-ArkUI组件(mediaquery)
- 9Android广播如何解决Sending non-protected broadcast问题
- 最近发表
-
- WooCommerce最好的WordPress常用插件下载博客插件模块的相关产品
- 羊驼机器人最好的WordPress常用插件下载博客插件模块
- IP信息记录器最好的WordPress常用插件下载博客插件模块
- Linkly for WooCommerce最好的WordPress常用插件下载博客插件模块
- 元素聚合器Forms最好的WordPress常用插件下载博客插件模块
- Promaker Chat 最好的WordPress通用插件下载 博客插件模块
- 自动更新发布日期最好的WordPress常用插件下载博客插件模块
- WordPress官方最好的获取回复WordPress常用插件下载博客插件模块
- Img to rss最好的wordpress常用插件下载博客插件模块
- WPMozo为Elementor最好的WordPress常用插件下载博客插件模块添加精简版