您现在的位置是:网站首页> 编程资料编程资料
基于mysql乐观锁实现秒杀的示例代码_Mysql_
2023-05-26
499人已围观
简介 基于mysql乐观锁实现秒杀的示例代码_Mysql_
说明
如果你的项目流量非常小,完全不用担心有并发的购买请求,那么做这样一个系统意义不大。但如果你的系统要像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
org.springframework.boot spring-boot-starter-web org.springframework.boot spring-boot-starter-test test org.mybatis.spring.boot mybatis-spring-boot-starter 1.3.0 mysql mysql-connector-java com.alibaba druid 1.1.10 com.alibaba druid-spring-boot-starter 1.1.10 com.github.pagehelper pagehelper 5.2.0 org.projectlombok lombok 1.18.8 org.junit.jupiter junit-jupiter 5.8.2 test
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
商品校验和减库存
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}
下订单
insert into stock_order (sid, name, create_time) values (#{sid,jdbcType=INTEGER}, #{name,jdbcType=VARCHAR}, #{createTime,jdbcType=TIMESTAMP})
6、service
public interface StockOrderService { public Integer createOrder(Integer id); }7、实现
/** * @author code * @Date 2022/6/24 9:25 * Description 订单实现 * Version 1.0 */ @Service public 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人参与活动
@SpringBootTest class 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乐观锁秒杀内容请搜索以前的文章或继续浏览下面的相关文章希望大家以后多多支持!
相关内容
- MySQL报错1040'Too many connections'的原因以及解决方案_Mysql_
- MySQL数据库误删回滚的解决_Mysql_
- mysql8报错:ERROR 1410 (42000): You are not allowed to create a user with GRANT解决办法_Mysql_
- MySQL开放远程连接权限的两种方法_Mysql_
- MySQL8.0开启远程连接权限的方法步骤_Mysql_
- 详细聊聊MySQL中auto_increment有什么作用_Mysql_
- MySql存储过程循环的使用分析详解_Mysql_
- 一次mysql的.ibd文件过大处理过程记录_Mysql_
- Navicat连接MySQL8.0的正确方法(亲测有效)_Mysql_
- Mysql通过ibd文件恢复数据的详细步骤_Mysql_
