当前位置:网站首页> 基于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乐观锁秒杀内容请搜索软件开发网以前的文章或继续浏览下面的相关文章希望大家以后多多支持软件开发网!
边栏推荐
猜你喜欢

Shell script imports stored procedures into the database

nexus搭建npm依赖私库

Different test techniques

Vs code setting Click to open a new file window without overwriting the previous window

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

Introduction to reverse debugging PE structure input table output table 05/07

Mobile note application

MySQL statistical bill information (Part 2): data import and query

The popular major I chose became "Tiankeng" four years later

leetcode:329. 矩阵中的最长递增路径【dfs + cache + 无需回溯 + 优雅】
随机推荐
基于开源流批一体数据同步引擎 ChunJun 数据还原 —DDL 解析模块的实战分享
科学创业三问:关于时机、痛点与重要决策
MHA high availability cluster deployment and failover of database
What are the solutions for session sharing of highly paid programmers & interview questions series 118?
Project deployment is not difficult at all!
CS5268优势替代AG9321MCQ Typec多合一扩展坞方案
天青色等烟雨
華為面試題: 招聘
简单斐波那契(递推)
Use Net core access wechat official account development
游戏公会在去中心化游戏中的未来
项目部署,一点也不难!
用.Net Core接入微信公众号开发
79. 单词搜索【dfs + 回溯visit + 遍历起点】
C language learning
Based on the open source stream batch integrated data synchronization engine Chunjun data restore DDL parsing module actual combat sharing
Will it affect the original MySQL database to read the data of a MySQL table in full by flick MySQL CDC
SSO and JWT good article sorting
Tencent security released the white paper on BOT Management | interpreting BOT attacks and exploring ways to protect
Introduction to reverse debugging PE structure input table output table 05/07