秒杀第十三节:交易模型管理-交易模型创建

2020-08-14  本文已影响0人  小石读史

首先创建用户下单的交易模型

@Data
public class OrderModel {
    //要用string
    private String id;

    private Integer userId;

    private Integer itemId;

    private BigDecimal itemPrice;

    private Integer amount;

    private BigDecimal orderPrice;

}

创建订单表并初始化部分数据用于测试

DROP TABLE IF EXISTS `order_info`;

CREATE TABLE `order_info` (
  `id` varchar(32) COLLATE utf8_unicode_ci NOT NULL DEFAULT '',
  `user_id` int(11) NOT NULL DEFAULT '0',
  `item_id` int(11) NOT NULL DEFAULT '0',
  `item_price` decimal(10,2) NOT NULL DEFAULT '0.00',
  `amount` int(11) NOT NULL DEFAULT '0',
  `order_price` decimal(10,2) NOT NULL DEFAULT '0.00',
  `promo_id` int(11) NOT NULL DEFAULT '0',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

/*Data for the table `order_info` */

insert  into `order_info`(`id`,`user_id`,`item_id`,`item_price`,`amount`,`order_price`,`promo_id`) values 
('2019041000000000',9,36,6999.00,1,6999.00,0),
('2019041000000100',9,36,6999.00,1,6999.00,0),
('2019041000000200',9,36,6999.00,1,6999.00,0),
('2019041200000300',9,40,200.00,1,200.00,2);

修改pom.xml将允许自动覆盖文件改为false,然后修改mybatis-generator.xml中的表为order_info,最后使用mybatis自动生成器生成基础服务。使用方式在秒杀第三节有说明
生成mapper文件和DO文件后新增OrderService类

public interface OrderService {

    //1.通过前端url上传过来秒杀活动id,然后
    //2.直接在下单接口内判断对应商品是否在秒杀
    OrderModel createOrder(Integer userId, Integer itemId,Integer amount) throws BussinessException;
}

实现OrderService 中的创建订单方法。创建订单分为以下几步:
1.校验下单状态(用户是否合法,下单商品是否存在,购买数量是否正确)
2.落单减库存
3.订单入库(生成交易流水号,订单号)
4.商品销量增加
5.返回前端
代码实现
首先在itemService中定义落单减库存和商品下单后对应销量增加接口

//库存扣减
 boolean decreaseStock(Integer itemId,Integer amount);

 //商品下单后对应销量增加
 void increaseSales(Integer itemId,Integer amount) throws BussinessException;

在ItemServiceImpl中实现itemService中的落单减库存和商品下单后对应销量增加接口

@Override
    @Transactional
    public boolean decreaseStock(Integer itemId, Integer amount) {

        int affectedRow = itemStockDOMapper.decreaseStock(itemId,amount);
        if(affectedRow > 0){
            return true;
        }else {
            return false;
        }
    }

    @Override
    @Transactional
    public void increaseSales(Integer itemId, Integer amount) throws BussinessException {
        itemDOMapper.increaseSales(itemId,amount);

    }

然后在对应itemStockDOMapper和itemDOMapper中实现落单减库存和商品下单后对应销量增加

int increaseSales(@Param("id")Integer id, @Param("amount")Integer amount);
int decreaseStock(@Param("itemId") Integer itemId, @Param("amount") Integer amount);
<update id="increaseSales">
update item
set sales = sales + #{amount}
where id = #{id,jdbcType=INTEGER}
</update>

<update id="decreaseStock">
update item_stock
set stock = stock - #{amount}
where item_id = #{itemId} and stock >= #{amount}
</update>

在订单入库的时候一般会生成交易流水号和订单号,订单号有16位,中间六位为自增序列,最后两位分库分表位
因为中间六位为自增序列,我们会设计一个表sequence_info来获取当前sequence,表结构如下:

DROP TABLE IF EXISTS `sequence_info`;

CREATE TABLE `sequence_info` (
  `name` varchar(255) COLLATE utf8_unicode_ci NOT NULL DEFAULT '',
  `current_value` int(11) NOT NULL DEFAULT '0',
  `step` int(11) NOT NULL DEFAULT '0',
  PRIMARY KEY (`name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

/*Data for the table `sequence_info` */

insert  into `sequence_info`(`name`,`current_value`,`step`) values 
('order_info',4,1);

修改pom.xml将允许自动覆盖文件改为false,然后修改mybatis-generator.xml中的表为sequence_info,最后使用mybatis自动生成器生成基础服务。使用方式在秒杀第三节有说明
OrderServiceImpl实现创建订单

@Service
public class OrderServiceImpl implements OrderService {

    @Autowired
    private ItemService itemService;
    @Autowired
    private UserService userService;

    @Autowired
    private OrderDOMapper orderDOMapper;

    @Autowired
    private SequenceDOMapper sequenceDOMapper;

    @Override
    @Transactional
    public OrderModel createOrder(Integer userId, Integer itemId,Integer amount) throws BussinessException {
        //1.校验下单状态(用户是否合法,下单商品是否存在,购买数量是否正确)
        ItemModel itemModel = itemService.getItemById(itemId);
        if(itemModel == null) {
            throw new BussinessException((EmBusinessError.PARAMETER_VALIDATION_ERROR),"商品不存在");
        }
        UserModel userModel = userService.getUserById(userId);
        if(userId == null) {
            throw new BussinessException(EmBusinessError.PARAMETER_VALIDATION_ERROR,"用户不存在");
        }
        if(amount <= 0 || amount > 99){
            throw new BussinessException(EmBusinessError.PARAMETER_VALIDATION_ERROR,"数量信息不正确");
        }


        //2.落单减库存,
        boolean result = itemService.decreaseStock(itemId,amount);
        if(!result) {
            throw new BussinessException(EmBusinessError.STOCK_NOT_ENOUGH);
        }

        //3.订单入库
        OrderModel orderModel = new OrderModel();
        orderModel.setUserId(userId);
        orderModel.setItemId(itemId);
        orderModel.setAmount(amount);
        orderModel.setItemPrice(itemModel.getPrice());
        orderModel.setOrderPrice(orderModel.getItemPrice().multiply(BigDecimal.valueOf(amount)));

        //生成交易流水号,订单号
        orderModel.setId(generatorOrderNo());
        OrderDO orderDO = convertFromOrderModel(orderModel);
        orderDOMapper.insertSelective(orderDO);
        //商品销量增加
        itemService.increaseSales(itemId,amount);
        //返回前端
        return orderModel;
    }


    @Transactional(propagation = Propagation.REQUIRES_NEW)
    String generatorOrderNo(){
        //1.订单号有16位
        StringBuilder stringBuilder = new StringBuilder();
        //前8位为时间信息,年月日
        LocalDateTime now = LocalDateTime.now();
        String nowDate = now.format(DateTimeFormatter.ISO_DATE).replace("-","");
        stringBuilder.append(nowDate);

        //2.中间六位为自增序列
        //获取当前sequence
        int sequence = 0;
        SequenceDO sequenceDO = sequenceDOMapper.selectByPrimaryKey("order_info");
        sequence = sequenceDO.getCurrentValue();
        sequenceDO.setCurrentValue(sequenceDO.getCurrentValue()+sequenceDO.getStep());
        sequenceDOMapper.updateByPrimaryKeySelective(sequenceDO);
        //凑足六位
        String sequenceStr = String.valueOf(sequence);
        for(int i = 0; i < 6 - sequenceStr.length(); i++) {
            stringBuilder.append(0);
        }
        stringBuilder.append(sequenceStr);

        //3.最后两位分库分表位
        stringBuilder.append("00");
        return stringBuilder.toString();
    }
    private OrderDO convertFromOrderModel(OrderModel orderModel){
        if(orderModel == null){
            return null;
        }
        OrderDO orderDO = new OrderDO();
        BeanUtils.copyProperties(orderModel,orderDO);
        return orderDO;
    }
}

OrderController封装下单

@Controller("/order")
@RequestMapping("/order")
@CrossOrigin(origins = {"*"}, allowCredentials = "true")
public class OrderController extends BaseController {

    @Autowired
    private OrderService orderService;

    @Autowired
    private HttpServletRequest httpServletRequest;

    //封装下单请求
    @RequestMapping(value = "/createorder", method = {RequestMethod.POST}, consumes = {CONTENT_TYPE_FORMED})
    @ResponseBody
    public CommonReturnType createOrder(@RequestParam(name="itemId")Integer itemId,
                                        @RequestParam(name="promoId",required = false)Integer promoId,
                                        @RequestParam(name="amount")Integer amount) throws BussinessException {

        //获取登录信息(Boolean)
        Boolean isLogin = (Boolean) this.httpServletRequest.getSession().getAttribute("IS_LOGIN");
        if(isLogin == null || !isLogin.booleanValue()){
            throw new BussinessException(EmBusinessError.USER_NOT_LOGIN,"用户还未登陆,不能下单");
        }
        UserModel userModel = (UserModel) this.httpServletRequest.getSession().getAttribute("LOGIN_USER");
        OrderModel orderModel = orderService.createOrder(userModel.getId(),itemId,amount);
        return CommonReturnType.create(null);

    }

}

下单测试参数:http://localhost:8080/order/createorder?itemId=41&amount=2
结果:

image.png
上一篇下一篇

猜你喜欢

热点阅读