当前位置:网站首页> 基于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乐观锁秒杀内容请搜索软件开发网以前的文章或继续浏览下面的相关文章希望大家以后多多支持软件开发网!
边栏推荐
- 买卖其实也有风险
- leetcode:329. 矩阵中的最长递增路径【dfs + cache + 无需回溯 + 优雅】
- There are risks in trading
- 哪个券商公司开户佣金低又安全又可靠
- Router.use() requires a middleware function but got a Object
- shell脚本导入存储过程到数据库
- 运行Powershell脚本提示“因为在此系统上禁止运行脚本”解决办法
- Tencent always takes epoll, which is annoying
- Mobile note application
- Use Net core access wechat official account development
猜你喜欢

项目部署,一点也不难!

使用nvm管理nodejs(把高版本降级为低版本)

Operator-1初识Operator

工具箱之 IKVM.NET 项目新进展

Fiori applications are shared through the enhancement of adaptation project

不同的测试技术区分

mysql统计账单信息(下):数据导入及查询

The future of game guild in decentralized games

Based on the open source stream batch integrated data synchronization engine Chunjun data restore DDL parsing module actual combat sharing

"Analysis of 43 cases of MATLAB neural network": Chapter 40 research on prediction of dynamic neural network time series -- implementation of NARX based on MATLAB
随机推荐
图灵奖得主Judea Pearl:最近值得一读的19篇因果推断论文
简单斐波那契(递推)
软件测试中功能测试流程
leetcode:226. 翻转二叉树【dfs翻转】
Using burpsuite to capture app packages
Zero copy technology of MySQL
mysql统计账单信息(下):数据导入及查询
codeforces -- 4B. Before an Exam
从数据库中更新一条数据,用cdc会同时获得op字段分别为d和c的两条数据吗?我记得之前是只有op为u
项目部署,一点也不难!
Operator-1 first acquaintance with operator
买卖其实也有风险
木架的场景功能
"Analysis of 43 cases of MATLAB neural network": Chapter 40 research on prediction of dynamic neural network time series -- implementation of NARX based on MATLAB
SQLAlchemy在删除有外键约束的记录时,外键约束未起作用,何解?
Scene function of wooden frame
[today in history] July 1: the father of time sharing system was born; Alipay launched barcode payment; The first TV advertisement in the world
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
基于开源流批一体数据同步引擎 ChunJun 数据还原 —DDL 解析模块的实战分享
Hardware development notes (9): basic process of hardware development, making a USB to RS232 module (8): create asm1117-3.3v package library and associate principle graphic devices