分布式锁实战(五)典型应用场景之书籍抢购


在实际的生产环境中,也确实可以看到分布式锁的身影,本节将以实际项目中典型业务场景“书籍抢购模块”为案例,巩固之前的知识

整体业务流程分析

在这里插入图片描述
上图中,不难发现,核心流程有三个
1.判读用户是否抢购过该商品
2.商品库存是否充足
3.更新书籍的库存并插入用户的抢购记录中
因此,又可以分成以下两大块
在这里插入图片描述

数据库设计

CREATE TABLE `book_stock` (
  `id` int(11) NOT NULL,
  `book_no` int(11) DEFAULT NULL COMMENT '书籍编号',
  `stock` varchar(255) COLLATE utf8mb4_bin DEFAULT NULL COMMENT '库存',
  `isActive` smallint(2) DEFAULT NULL COMMENT '是否上架(1上,0不是)',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;

CREATE TABLE `book_rob` (
  `id` int(8) NOT NULL AUTO_INCREMENT COMMENT '主键id',
  `user_id` int(8) DEFAULT NULL COMMENT '用户id',
  `book_no` int(8) DEFAULT NULL COMMENT '书籍编号',
  `rob_time` datetime DEFAULT NULL COMMENT '抢购时间',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
package com.learn.boot.controller;


import com.learn.boot.dto.BookRobDto;
import com.learn.boot.mapper.redis.book.BookRobMapper;
import com.learn.boot.mapper.redis.book.BookStockMapper;
import com.learn.boot.mapper.redis.log.SysLogMapper;
import com.learn.boot.mapper.test.AMapper;
import com.learn.boot.model.*;
import com.learn.boot.resultVo.ResultVo;
import com.learn.boot.service.DemoService;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.recipes.locks.InterProcessSemaphoreMutex;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.*;

import java.util.Date;
import java.util.concurrent.TimeUnit;

/**
 * author: zlx
 * date: 2020-1-1 17:17
 * desc:
 **/
@RestController
public class BookController {
    private static final Logger log = LoggerFactory.getLogger(BookController.class);
    @Autowired
    private BookRobMapper bookRobMapper;

    @Autowired
    private BookStockMapper bookStockMapper;

    /**
     * 使用CuratorFramework实现分布式锁,在CuratorFrameworkConfig重写了
     */
    @Autowired
    private CuratorFramework curatorFramework;

    @RequestMapping(value = "/bookRob",method = RequestMethod.POST)
    @Transactional(rollbackFor = Exception.class)
    public ResultVo main(@RequestBody BookRobDto dto, BindingResult bindingResult) {
        try {
            if (bindingResult.hasErrors()) {
                return ResultVo.error("请求参数异常");
            }
            // 判断此书籍是否能够被抢购
            BookStock bookStock = bookStockMapper.selectBookRobByBookNo(dto.getBookNo());
            if (bookStock == null || Integer.valueOf(bookStock.getStock()) <= 0) {
                return ResultVo.error("库存不足");
            }
            // 先查询用户是否抢购过此书籍
            Integer buyedTotal = bookRobMapper.countByBookNoUserId(dto.getUserId(), dto.getBookNo());

            if (buyedTotal == null) {
                return ResultVo.error("您已抢购过该书籍");
            }
            // 抢购成功,更新库存
            String lockName = "/local/book";
            InterProcessSemaphoreMutex lock = new InterProcessSemaphoreMutex (curatorFramework, lockName);
            if (lock.acquire(15L, TimeUnit.SECONDS)) {
                log.info("开始抢购");
                bookStock.setStock(String.valueOf(Integer.valueOf(bookStock.getStock()) - 1));
                int res = bookStockMapper.updateByPrimaryKey(bookStock);
                log.info("更新库存完成");
                if (res > 0 ) {
                    // 创建书籍抢购记录实体信息
                    BookRob entity=new BookRob();
                    // 从提交的用户抢购请求实体信息中对应的字段取值
                    // 复制到新创建的书籍抢购记录实体的相应字段中
                    BeanUtils.copyProperties(dto,entity);
                    // 设置抢购时间
                    entity.setRobTime(new Date());
                    // 插入用户注册信息
                    bookRobMapper.insertSelective(entity);
                    log.info("插入抢购记录成功");
                }
                return ResultVo.success("抢购成功");
            }

            return ResultVo.error("抢购失败");
        }catch (Exception ex){
            log.info("异常1",ex);
            return ResultVo.error();
        }
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值