秒杀的实现和解决超卖问题

秒杀的实现和解决超卖问题

关于超卖问题

由于mysql是多线程,而且在磁盘上进行工作,如果两个用户同时下单,二商品库存只有一个,会出现同时下单成功,这时就需要用到MySQL的乐观锁和悲观锁机制,不过秒杀机制还有一个重要的地方就高并发,高并发推荐使用redis这种在内存工作的数据库,不过本片先介绍关于超卖的问题

创建商品表和订单表

在这里插入图片描述
在这里插入图片描述

创建与表相关实体类

编写mapper接口及实现

public interface GoodsMapper {

    /**

     * 减掉商品库存——悲观锁

     * @return

     */

    @Update("UPDATE `databaseset`.`seckill_goods` SET `name` = 'iphone X', `count` = #{goods.count}, `sale` = #{goods.sale}, `version` = 0 WHERE `id` = 1 ;")   //for update

    int updateGoodsCount(@Param("goods") Goods goods);



    /**

     * 减掉商品库存——乐观锁

     * @return

     */

    @Update("UPDATE `databaseset`.`seckill_goods` SET `name` = 'iphone X', `count` = #{goods.count}, `sale` = #{goods.sale}, `version` = #{goods.version}+1 WHERE `id` = #{goods.id} and version = #{updateVersion};")

    int updateGoodsCountOptimisticLock(@Param("goods")Goods goods, @Param("updateVersion")int version);



    /**

     * 查询商品

     * @return

     */

    @Select("select `id`, `name`, `count`, `sale`, `version` from seckill_goods where id = 1 for update;")

    Goods getGoods();

}

public interface OrderMapper {



    /**

     * 生成订单

     * @param name

     * @param createTime

     * @return

     */

    @Insert("INSERT INTO `databaseset`.`seckill_order`(`custname`, `create_time`) VALUES (#{name}, #{createTime});")

    int insertOrder(@Param("name") String name, @Param("createTime") String createTime);



}

Service层接口及实现

根据mapper层提供的一些对数据库的操作方法,更进一步实现秒杀功能

悲观锁实现
悲观锁更多的是在数据库操作,当表进行修改时,会把表锁住。直到修改成功

public void seckillPessimi**sm()** throws Exception {

    //悲观锁begin

    SqlSession sqlSession = sqlSessionFactory.openSession(false);

    sqlSession.getConnection().setAutoCommit(false);



    //查询库存,如果库存大于0,则继续秒杀逻辑

    Goods goods = goodsService.getGoods();

    if (null != goods && goods.getCount() <= 0) {

        System.out.println(Thread.currentThread().getName() + "悲观锁方式商品卖光了!!!当前时间:" + System.currentTimeMillis());

        return;

    }



    //库存-1,销量+1

    Goods goodsForUpdate = new Goods();

    goodsForUpdate.setCount(goods.getCount()-1);

    goodsForUpdate.setSale(goods.getSale()+1);

    goodsForUpdate.setId(1);

    int i = goodsService.updateGoodsCount(goodsForUpdate);



    //当库存更新成功后创建订单

    if(1>0){

        //创建订单

        String time = System.currentTimeMillis()+"";

        String custname = "zhangsan"+time.substring(8,time.length());

        String createTime = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());

        insertOrder(custname,createTime);

    }



    sqlSession.getConnection().commit();

}

乐观锁的实现
乐观锁更多是在表中多加一个字段,一般叫version,当表进行修改时,会提取version,提交修改时,会再次提取version值与之前version做标记,如果不一样则修改失败

public void seckillOptimistic() {

    //查询库存,如果库存大于0,则继续秒杀逻辑

    Goods goods = goodsService.getGoods();

    if (null != goods && goods.getCount() <= 0) {

        System.out.println(Thread.currentThread().getName() + "乐观锁方式商品卖光了!!!当前时间:" + System.currentTimeMillis());

        return;

    }

    int currentVersion = goods.getVersion();

    Goods goodsForUpdate = new Goods();

    goodsForUpdate.setVersion(currentVersion);

    goodsForUpdate.setCount(goods.getCount()-1);

    goodsForUpdate.setSale(goods.getSale()+1);

    goodsForUpdate.setId(1);

    int i = goodsService.updateGoodsCountOptimisticLock(goodsForUpdate,currentVersion);



    //当库存更新成功后创建订单

    if(1>0){

        String time = System.currentTimeMillis()+"";

        String custname = "zhangsan"+time.substring(8,time.length());

        String createTime = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());

        insertOrder(custname,createTime);

    }

}


乐观锁失败后的重试

public int seckillWithOptimistic() {



    //查询库存,如果库存大于0,则继续秒杀逻辑

    Goods goods = goodsService.getGoods();

    if (null != goods && goods.getCount() <= 0) {

        System.out.println(Thread.currentThread().getName() + "乐观锁方式商品卖光了!!!当前时间:" + System.currentTimeMillis());

        return -1;

    }

    int currentVersion = goods.getVersion();

    Goods goodsForUpdate = new Goods();

    goodsForUpdate.setVersion(currentVersion);

    goodsForUpdate.setCount(goods.getCount()-1);

    goodsForUpdate.setSale(goods.getSale()+1);

    goodsForUpdate.setId(1);

    int i = goodsService.updateGoodsCountOptimisticLock(goodsForUpdate,currentVersion);



    //当库存更新成功后创建订单

    if(1>0){

        String time = System.currentTimeMillis()+"";

        String custname = "zhangsan"+time.substring(8,time.length());

        String createTime = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());

        insertOrder(custname,createTime);

        return 1;

    }else{      //乐观锁如何重试呢?

        return 0;

    }

}

使用redis进行秒杀

public void seckillwithRedis() {

    String key = "seckill";     //定义一个key,key的值就是商品的数量

    long count = stringRedisTemplate.opsForValue().increment(key,-1l);

    if(count >=0 ){

        //创建订单

        String time = System.currentTimeMillis()+"";

        String name = "zhangsan"+time.substring(8,time.length());

        String createTime = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());

        insertOrder(name,createTime);

    }else{

        System.out.println("卖光了"+System.currentTimeMillis());

    }

}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值