Java自学者论坛

 找回密码
 立即注册

手机号码,快捷登录

恭喜Java自学者论坛(https://www.javazxz.com)已经为数万Java学习者服务超过8年了!积累会员资料超过10000G+
成为本站VIP会员,下载本站10000G+会员资源,会员资料板块,购买链接:点击进入购买VIP会员

JAVA高级面试进阶训练营视频教程

Java架构师系统进阶VIP课程

分布式高可用全栈开发微服务教程Go语言视频零基础入门到精通Java架构师3期(课件+源码)
Java开发全终端实战租房项目视频教程SpringBoot2.X入门到高级使用教程大数据培训第六期全套视频教程深度学习(CNN RNN GAN)算法原理Java亿级流量电商系统视频教程
互联网架构师视频教程年薪50万Spark2.0从入门到精通年薪50万!人工智能学习路线教程年薪50万大数据入门到精通学习路线年薪50万机器学习入门到精通教程
仿小米商城类app和小程序视频教程深度学习数据分析基础到实战最新黑马javaEE2.1就业课程从 0到JVM实战高手教程MySQL入门到精通教程
查看: 6255|回复: 0

Java之秒杀活动解决方案

[复制链接]
  • TA的每日心情
    奋斗
    2024-11-24 15:47
  • 签到天数: 804 天

    [LV.10]以坛为家III

    2053

    主题

    2111

    帖子

    72万

    积分

    管理员

    Rank: 9Rank: 9Rank: 9

    积分
    726782
    发表于 2021-4-16 15:20:26 | 显示全部楼层 |阅读模式

    引言

      本文主要描述,服务端做相关秒杀活动的时候,对应的解决方案,即高并发下的数据安全。

    优化方案

    乐观锁思路

      Redis中的watch,请求时,通过Redis查询当前抢购数据,如果当前抢购数据已经到达临界值,则直接提示相应的页面/信息,如返回已抢购完的页面。

    分布式限流

      当然,对于很大量的秒杀,可以准备多个Redis实例,用户请求时,可以随机数或者散列取模,找对应实例来进行抢购。

      采用Redis有一个好处,比如支持很多应用服务器一起抢……

    提高吞吐量

      Nigix反向代理+负载均衡

    实现流程

      其实抛开秒杀这个场景来说正常的一个下单流程可以简单分为以下几步:

    • 校验库存
    • 扣库存
    • 创建订单
    • 支付
    Transactional(rollbackFor = Exception.class)
    @Service(value = "DBOrderService")
    public class OrderServiceImpl implements OrderService {
        @Resource(name = "DBStockService")
        private com.crossoverJie.seconds.kill.service.StockService stockService;
    
        @Autowired
        private StockOrderMapper orderMapper;
        
        @Override
        public int createWrongOrder(int sid) throws Exception{
    
            //校验库存
            Stock stock = checkStock(sid);
    
            //扣库存
            saleStock(stock);
    
            //创建订单
            int id = createOrder(stock);
    
            return id;
        }
        
        private Stock checkStock(int sid) {
            Stock stock = stockService.getStockById(sid);
            if (stock.getSale().equals(stock.getCount())) {
                throw new RuntimeException("库存不足");
            }
            return stock;
        }
        
        private int saleStock(Stock stock) {
            stock.setSale(stock.getSale() + 1);
            return stockService.updateStockById(stock);
        }
        
        private int createOrder(Stock stock) {
            StockOrder order = new StockOrder();
            order.setSid(stock.getId());
            order.setName(stock.getName());
            int id = orderMapper.insertSelective(order);
            return id;
        }        
            
    }
    

      其实其他的都没怎么改,主要是 Service 层。

      @Override
        public int createOptimisticOrder(int sid) throws Exception {
    
            //校验库存
            Stock stock = checkStock(sid);
    
            //乐观锁更新库存
            saleStockOptimistic(stock);
    
            //创建订单
            int id = createOrder(stock);
    
            return id;
        }
        
        private void saleStockOptimistic(Stock stock) {
            int count = stockService.updateStockByOptimistic(stock);
            if (count == 0){
                throw new RuntimeException("并发更新库存失败") ;
            }
        }
    

      对应的 XML:

    <update id="updateByOptimistic" parameterType="com.crossoverJie.seconds.kill.pojo.Stock">
            update stock
            <set>
                sale = sale + 1,
                version = version + 1,
            </set>
    
            WHERE id = #{id,jdbcType=INTEGER}
            AND version = #{version,jdbcType=INTEGER}
    
        </update>
    

    如何保持高并发下数据一致性

      对多个更新操作的业务加事物注解。在数据库表中加一个vesion版本控制字段(初始值为0)在更新操作前查询并记录该字段,更新操作完成vesion+1,再次查询vesion与更新操作前记录的值相差1说明前后数据一致,否则回滚更新操作

    哎...今天够累的,签到来了1...
    回复

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    QQ|手机版|小黑屋|Java自学者论坛 ( 声明:本站文章及资料整理自互联网,用于Java自学者交流学习使用,对资料版权不负任何法律责任,若有侵权请及时联系客服屏蔽删除 )

    GMT+8, 2025-2-5 15:43 , Processed in 0.061110 second(s), 29 queries .

    Powered by Discuz! X3.4

    Copyright © 2001-2021, Tencent Cloud.

    快速回复 返回顶部 返回列表