当前位置:网站首页> 基于mysql乐观锁实现秒杀的示例代码
基于mysql乐观锁实现秒杀的示例代码
2022-07-01 12:59:00 【1024问】
说明
具体实现
代码实现
说明如果你的项目流量非常小,完全不用担心有并发的购买请求,那么做这样一个系统意义不大。但如果你的系统要像12306那样,接受高并发访问和下单的考验,那么你就需要一套完整的流程保护措施,来保证你系统在用户流量高峰期不会被搞挂了。
进阶redis+mq实现:参考springboot + rabbitmq + redis实现秒杀
具体实现严格防止超卖
保证用户体验:高并发下,别网页打不开了,支付不成功了,购物车进不去了,地址改不了了
防止黑产:防止不怀好意的人群通过各种技术手段把你本该下发给群众的利益全收入了囊中
1、核心
mysql乐观锁防止超卖
乐观锁是指操作数据库时(更新操作),想法很乐观,认为这次的操作不会导致冲突,在操作数据时,并不进行任何其他的特殊处理(也就是不加锁),而在进行更新后,再去判断是否有冲突了。
这里是引用通常实现是这样的:在表中的数据进行操作时(更新),先给数据表加一个版本(version)字段,每操作一次,将那条记录的版本号加1。也就是先查询出那条记录,获取出version字段,如果要对那条记录进行操作(更新),则先判断此刻version的值是否与刚刚查询出来时的version的值相等,如果相等,则说明这段期间,没有其他程序对其进行操作,则可以执行更新,将version字段的值加1;如果更新时发现此刻的version值与刚刚获取出来的version的值不相等,则说明这段期间已经有其他程序对其进行操作了,则不进行更新操作。
2、建表语句
stock商品表
-- ------------------------------ Table structure for stock-- ----------------------------DROP TABLE IF EXISTS `stock`;CREATE TABLE `stock` ( `id` int(11) unsigned NOT NULL AUTO_INCREMENT, `name` varchar(50) NOT NULL DEFAULT '' COMMENT '名称', `count` int(11) NOT NULL COMMENT '库存', `sale` int(11) NOT NULL COMMENT '已售', `version` int(11) NOT NULL COMMENT '乐观锁,版本号', PRIMARY KEY (`id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8;初始化数据:

stock_order订单表
-- ------------------------------ Table structure for stock_order-- ----------------------------DROP TABLE IF EXISTS `stock_order`;CREATE TABLE `stock_order` ( `id` int(11) unsigned NOT NULL AUTO_INCREMENT, `sid` int(11) NOT NULL COMMENT '库存ID', `name` varchar(30) NOT NULL DEFAULT '' COMMENT '商品名称', `create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '创建时间', PRIMARY KEY (`id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8;3、业务流程

1、pom
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <!--mysql--> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>1.3.0</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency> <!--druid--> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.1.10</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid-spring-boot-starter</artifactId> <version>1.1.10</version> </dependency> <dependency> <groupId>com.github.pagehelper</groupId> <artifactId>pagehelper</artifactId> <version>5.2.0</version> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.8</version> </dependency> <dependency> <groupId>org.junit.jupiter</groupId> <artifactId>junit-jupiter</artifactId> <version>5.8.2</version> <scope>test</scope> </dependency>2、model

可通过逆向工程进行配置,参考idea+mybatis逆向工程
4、dao
public interface StockMapper { Stock checkStock(Integer id);//校验库存 int updateSale(Stock stock);//扣除库存}public interface StockOrderMapper { //创建订单 void createOrder(StockOrder order);}5、sql
商品校验和减库存
<select id="checkStock" parameterType="java.lang.Integer" resultType="com.yy.msserver.model.vo.Stock"> select * from stock where id = #{id} </select> <update id="updateSale" parameterType="com.yy.msserver.model.vo.Stock" > update stock set sale = #{sale,jdbcType=INTEGER} + 1, version = #{version,jdbcType=INTEGER} + 1, count = #{count,jdbcType=INTEGER} - 1 where id = #{id,jdbcType=INTEGER} AND count > 0 AND version = #{version} </update>下订单
<insert id="createOrder" parameterType="com.yy.msserver.model.vo.StockOrder"> insert into stock_order (sid, name, create_time) values (#{sid,jdbcType=INTEGER}, #{name,jdbcType=VARCHAR}, #{createTime,jdbcType=TIMESTAMP}) </insert>6、service
public interface StockOrderService { public Integer createOrder(Integer id);}7、实现
/** * @author code * @Date 2022/6/24 9:25 * Description 订单实现 * Version 1.0 */@Servicepublic class StockOrderServiceImpl implements StockOrderService { @Autowired private StockOrderMapper stockOrderMapper; @Autowired private StockMapper stockMapper; @Override @Transactional(rollbackFor = Exception.class) public Integer createOrder(Integer id) { //校验库存 Stock stock = checkStock(id); if(stock.getCount()>0){ System.out.println("当前库存:" + stock.getCount()); //扣库存 if(updateSale(stock) == 1){ return createOrder(stock); }else { return 0; } } return 0; } //校验库存 private Stock checkStock(Integer id) { return stockMapper.checkStock(id); } //扣库存 private int updateSale(Stock stock){ return stockMapper.updateSale(stock); } //下订单 private Integer createOrder(Stock stock){ StockOrder order = new StockOrder(); order.setSid(stock.getId()); order.setCreateTime(new Date()); order.setName(stock.getName()); stockOrderMapper.createOrder(order); return order.getId(); }}8、测试
模拟100人参与活动
@SpringBootTestclass MsServerApplicationTests { @Autowired private StockOrderService stockOrderService; @Test void contextLoads() throws InterruptedException { // 库存初始化为10,这里通过CountDownLatch和线程池模拟100个并发 int threadTotal = 100; ExecutorService executorService = Executors.newCachedThreadPool(); final CountDownLatch countDownLatch = new CountDownLatch(threadTotal); for (int i = 0; i < threadTotal ; i++) { int uid = i; executorService.execute(() -> { try { stockOrderService.createOrder(1); } catch (Exception e) { e.printStackTrace(); } countDownLatch.countDown(); }); } countDownLatch.await(); executorService.shutdown(); }}9、结果

商品表

订单表

到此这篇关于基于mysql乐观锁实现秒杀的示例代码的文章就介绍到这了,更多相关mysql乐观锁秒杀内容请搜索软件开发网以前的文章或继续浏览下面的相关文章希望大家以后多多支持软件开发网!
边栏推荐
- 我花上万学带货:3天赚3元,成交靠刷单
- 晓看天色暮看云,美图欣赏
- oracle cdc 数据传输时,clob类型字段,在update时值会丢失,update前有值,但
- VS Code 设置代码自动保存
- CV顶会最佳论文得主分享:好论文是怎么炼成的?
- [Niu Ke's questions -sql big factory interview real questions] no2 User growth scenario (a certain degree of information flow)
- 不同的测试技术区分
- 79. 单词搜索【dfs + 回溯visit + 遍历起点】
- Eurake partition understanding
- Digital signal processing -- Design of linear phase (Ⅱ, Ⅳ) FIR filter (2)
猜你喜欢

MHA high availability cluster deployment and failover of database

Different test techniques

Fiori applications are shared through the enhancement of adaptation project

【大型电商项目开发】性能压测-压力测试基本概念&JMeter-38

Mobile note application

王兴的无限游戏迎来“终极”一战

路由基础之OSPF LSA详细讲解

游戏公会在去中心化游戏中的未来

Redis explores cache consistency

nexus搭建npm依赖私库
随机推荐
Eurake partition understanding
CS5268优势替代AG9321MCQ Typec多合一扩展坞方案
下半年还有很多事要做
R language builds a binary classification model based on H2O package: using H2O GBM build gradient hoist model GBM, use H2O AUC value of AUC calculation model
PG基础篇--逻辑结构管理(触发器)
How to play with the reading and writing operations of blocking sockets?
机器学习—性能度量
MHA high availability cluster deployment and failover of database
Which securities company has a low, safe and reliable account opening commission
mysql统计账单信息(下):数据导入及查询
题目 1004: 母牛的故事(递推)
工具箱之 IKVM.NET 项目新进展
flinkcdc要实时抽取oracle,对oracle要配置什么东西?
Class initialization and instantiation
leetcode:241. Design priority for operation expression [DFS + Eval]
leetcode 322. Coin Change 零钱兑换(中等)
软件测试中功能测试流程
网络socket的状态要怎么统计?
有没有大佬 遇到过flink监控postgresql数据库, 检查点无法使用的问题
be based on. NETCORE development blog project starblog - (13) add friendship link function