# SpringBoot 秒杀项目 **Repository Path**: WcGqQ/secondkill ## Basic Information - **Project Name**: SpringBoot 秒杀项目 - **Description**: 基于 SpringBoot 、MyBatis 、Redis 构建秒杀系统,带你了解悲观锁、乐观锁及解决方法。 - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 4 - **Created**: 2022-10-18 - **Last Updated**: 2022-10-18 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # 一、仓库介绍 * ### 背景:常见高并发场景 -- 抢购商品 * ### 技术:SpringBoot、MyBatis、Redis 从 0 开始认识高并发,介绍悲观锁、乐观锁及其解决方案,最终使用 redis 应对高并发场景。 # 二、仓库使用与学习 开发过程,每一个版本都打上了对应标签,下方即为各版本介绍。 可以直接查看指定版本学习,或者从 1.0 开始逐层推进。 #### 注意:由于环境的原因,某些版本可能没有达到预期效果,学习时可根据实际情况理解不同版本之间的区别。 # 三、克隆运行步骤 > 数据库名称:`second_kill` > 开发使用的 SQL 语句,位于 `src/resources/sql` 下 * 安装 MySQL、Redis * 创建数据库、表,初始化表数据 * 修改项目配置文件中 MySQL 连接密码 * Maven 安装项目依赖 * 启动项目 * 访问 http://127.0.0.1:8080,查看数据库商品数据 --- # 版本 1.0 ### 条件: * 请求量:50000 * 初始库存:20000 使用浏览器模拟高并发,点击抢购按钮时发送 50000 个请求,同时更新当前请求数 ### 问题: * 请求可以发送,但 50000 个请求时间过长,按钮按下后距离弹起的时间过长,浏览器直接卡死 * 在连续发送请求的同时,浏览器无法更新 dom 元素(可能是我电脑太差......),请求数卡死在 0 # 版本 1.1 点击按钮发送请求 改为 进入页面自动请求,去掉更新请求数的行为 在控制台打印请求数 ### 问题: * 进入页面请求即开始,浏览器卡到根本打不开控制台(放弃查看当前请求数......) # 版本 1.2 50000 的请求量太大,电脑总是崩溃,无法请求完成 ### 修改: * 请求量:10000 商品初始库存:5000 ### 结果: * 请求顺利完成 * 出现超发现象,最后库存为 -1 * 请求总时长大约为 40 秒 ### 结果图: 库存: ![库存](./image/1.2超发.png) 时间: ![时间](./image/1.2时间.png) # 版本 2.0 为避免超发现象,使用悲观锁 ### 结果: * 顺利解决超发现象,最后库存为 0 * 请求时间延长 使用悲观锁的代价就是请求时间延长,因为悲观锁会锁定每次查询到的数据,直到当前事务完成后其他事务才能访问 ### 结果图: 库存: ![库存](./image/2.0库存.png) 时间: ![时间](./image/2.0时间.png) # 版本 3.0 为提高性能,使用乐观锁 同时,为了避免 ABA 问题,修改操作加上版本号 ### 结果: * 请求时间与不加锁时相近,性能损失很小 * 从库存图片可以看出,请求结束时库存不为 0 乐观锁中,由于版本号的原因,会出现大量更新失败的请求 ### 结果图: 库存: ![库存](./image/3.0库存.png) 时间: ![时间](./image/3.0时间.png) # 版本 3.1 为降低使用乐观锁时请求的失败率,加入重入机制 使用时间戳限制重入,规定 100 ms 内可重试更新操作 ### 结果: * 请求结束时,库存为 0 但是使用时间戳重入的方法也有弊端,就是系统会随着自身的忙碌而大大减少重入的次数 ### 结果图: 库存: ![库存](./image/3.1库存.png) 时间: ![时间](./image/3.1时间.png) # 版本 3.2 为解决时间戳重入的弊端,使用限定次数的重入机制,即一定的次数内可重入 具体的限定次数可以根据实际情况修改,这里限定重入次数为 3 次 ### 结果: * 具体使用时,限定次数的重入也应当大大降低失败次数,可能是不同环境的原因,这里的失败次数反而更多了...... 具体生产环境中,使用乐观锁时,重入方法需要视情况选择,但是更推荐大家使用 redis 来应对高并发场景 ### 结果图: 库存: ![库存](./image/3.2库存.png) 时间: ![时间](./image/3.2时间.png) # 版本 4.0 使用 redis 应对高并发场景 redis 保存商品信息,购买记录直接保存在 redis 中,抢购结束后定时将数据写入到数据库即可 ### 特点: * redis 直接保存在内存中,读写速度非常快 * 使用 lua 语言编写脚本完成业务,业务执行具有原子性,不会出现超发现象 * 抢购数据直接从 redis 上读取,减小数据库压力 ### 结果: * 请求完成后,无超发现象 * 请求时间缩短至 3 秒 ### 结果图: 库存: ![库存](./image/4.0库存.png) 时间: ![时间](./image/4.0时间.png)