Redisson分布式锁使用场景

并发的场景下,用户在生成订单时,需要进行使用分布式锁来锁定商品库存,避免出现超卖情况

以下是三大优选团购系统中完整的下单处理流程和逻辑

1. 确认订单处理逻辑(生成唯一标识订单号,存入redis,用于生成订单时进行验证)

//确认订单
    @Override
    public OrderConfirmVo confirmOrder() {
        //获取用户id
        Long userId = AuthContextHolder.getUserId();

        //获取用户对应团长信息
        LeaderAddressVo leaderAddressVo =
                userFeignClient.getUserAddressByUserId(userId);

        //获取购物车里面选中的商品
        List<CartInfo> cartInfoList = cartFeignClient.getCartCheckedList(userId);

        //唯一标识订单号,存入redis
        String orderNo = System.currentTimeMillis() + "";
        redisTemplate.opsForValue().set(RedisConst.ORDER_REPEAT + orderNo, orderNo,
                24, TimeUnit.HOURS);

        //获取购物车满足条件活动和优惠卷信息
        OrderConfirmVo orderConfirmVo = activityFeignClient.findCartActivityAndCoupon(cartInfoList, userId);

        //封装其他值
        orderConfirmVo.setLeaderAddressVo(leaderAddressVo); //团长地址
        orderConfirmVo.setOrderNo(orderNo); //订单号

        return orderConfirmVo;
    }

2. 生成订单处理逻辑

//生成订单
    @Transactional
    @Override
    public Long submitOrder(OrderSubmitVo orderParamVo) {
        //第一步 设置给哪个用户生成订单  设置orderParamVo的userId
        Long userId = AuthContextHolder.getUserId();
        orderParamVo.setUserId(userId);

        //第二步 订单不能重复提交,重复提交验证
        // 通过redis + lua脚本进行判断
         lua脚本保证原子性操作
        //1 获取传递过来的订单 orderNo
        String orderNo = orderParamVo.getOrderNo();
        if(StringUtils.isEmpty(orderNo)) {
            throw new SdyxException(ResultCodeEnum.ILLEGAL_REQUEST);
        }

        //2 拿着 orderNo 到 redis 进行查询,
        String script = "if(redis.call('get', KEYS[1]) == ARGV[1]) then return redis.call('del', KEYS[1]) else return 0 end";
        //3 如果redis有相同orderNo(确认订单成功存到redis),表示正常提交订单,把redis的orderNo删除(即生成订单后需要把锁定的订单从redis删除)
        Boolean flag = (Boolean)redisTemplate
                        .execute(new DefaultRedisScript(script, Boolean.class),
                                    Arrays.asList(RedisConst.ORDER_REPEAT + orderNo), orderNo);
        //4 如果redis没有相同orderNo,表示重复提交了,不能再往后进行
        if(!flag) {
            throw new SdyxException(ResultCodeEnum.REPEAT_SUBMIT);
        }

        //第三步 验证库存 并且 锁定库存
        // 比如仓库有10个西红柿,我想买2个西红柿
        // ** 验证库存,查询仓库里面是是否有充足西红柿
        // ** 库存充足,库存锁定 2 锁定(目前没有真正减库存)
        //1、远程调用service-cart模块,获取当前用户购物车商品(选中的购物项)
        List<CartInfo> cartInfoList =
                        cartFeignClient.getCartCheckedList(userId);

        //2、购物车有很多商品,商品不同类型,重点处理普通类型商品
        List<CartInfo> commonSkuList = cartInfoList.stream()
                .filter(cartInfo -> cartInfo.getSkuType() == SkuType.COMMON.getCode())
                .collect(Collectors.toList());

        //3、把获取购物车里面普通类型商品list集合,
        // List<CartInfo>转换List<SkuStockLockVo> 便于验证sku库存和锁定sku库存
        if(!CollectionUtils.isEmpty(commonSkuList)) {
            List<SkuStockLockVo> commonStockLockVoList = commonSkuList.stream().map(item -> {
                SkuStockLockVo skuStockLockVo = new SkuStockLockVo();
                skuStockLockVo.setSkuId(item.getSkuId());
                skuStockLockVo.setSkuNum(item.getSkuNum());
                return skuStockLockVo;
            }).collect(Collectors.toList());

            //4、远程调用service-product模块实现锁定商品
             验证库存并锁定库存,保证具备原子性
            Boolean isLockSuccess =
                    productFeignClient.checkAndLock(commonStockLockVoList, orderNo);
            if(!isLockSuccess) { //库存锁定失败
                throw new SdyxException(ResultCodeEnum.ORDER_STOCK_FALL);
            }
        }

        //第四步 下单过程
        //1 向两张表添加数据
        // order_info 和 order_item
        Long orderId = this.saveOrder(orderParamVo, cartInfoList);

        //下单完成,删除购物车记录
        //发送mq消息(交换机、路由键、消息)
        rabbitService.sendMessage(MqConst.EXCHANGE_ORDER_DIRECT, MqConst.ROUTING_DELETE_CART, orderParamVo.getUserId());

        //第五步 返回订单id
        return orderId;
    }

2.1 验证商品库存并锁定库存

/**
     * 验证和锁定库存
     * @param skuStockLockVoList
     * @param orderNo
     * @return 订单中所有商品锁定成功,返回true, 只要有一个商品锁定失败,返回false
     */
    @Override
    public Boolean checkAndLock(List<SkuStockLockVo> skuStockLockVoList, String orderNo) {
        //1 判断skuStockLockVoList集合是否为空
        if(CollectionUtils.isEmpty(skuStockLockVoList)) {
            throw new SdyxException(ResultCodeEnum.DATA_ERROR);
        }

        //2 遍历skuStockLockVoList得到每个商品,验证库存并锁定库存,具备原子性
        skuStockLockVoList.stream().forEach(skuStockLockVo -> {
            this.checkLock(skuStockLockVo);
        });

        //3 只要有一个商品锁定失败(isLock字段值为false),所有锁定成功的商品都解锁
        boolean flag = skuStockLockVoList.stream()
                .anyMatch(skuStockLockVo -> !skuStockLockVo.getIsLock());
        if(flag) {
            //所有锁定成功的商品都解锁
            skuStockLockVoList.stream().filter(SkuStockLockVo::getIsLock)
                    .forEach(skuStockLockVo -> {
                        baseMapper.unlockStock(skuStockLockVo.getSkuId(), skuStockLockVo.getSkuNum());
                    });
            //返回失败的状态
            return false;
        }

        //4 如果所有商品都锁定成功了,redis缓存相关数据,为了方便后面解锁和减库存
        redisTemplate.opsForValue()
                .set(RedisConst.SROCK_INFO + orderNo, skuStockLockVoList);
        return true;
    }

2.2 使用Redisson的公平锁实现锁定库存

//2 遍历skuStockLockVoList得到每个商品,验证库存并锁定库存,具备原子性
    private void checkLock(SkuStockLockVo skuStockLockVo) {
//        获取锁
//        公平锁
        RLock rLock =
                this.redissonClient.getFairLock(RedisConst.SKUKEY_PREFIX + skuStockLockVo.getSkuId());
        //加锁
        rLock.lock();
        try {
            //验证库存
            SkuInfo skuInfo =
                    baseMapper.checkStock(skuStockLockVo.getSkuId(), skuStockLockVo.getSkuNum());
            //判断没有满足条件商品,设置isLock值false,返回
            if(skuInfo == null) {
                skuStockLockVo.setIsLock(false); //设置锁定失败
                return;
            }

            //有满足条件商品
            //锁定库存:update
            Integer rows =
                    baseMapper.lockStock(skuStockLockVo.getSkuId(), skuStockLockVo.getSkuNum());
            if(rows == 1) {
                skuStockLockVo.setIsLock(true); //设置锁定成功
            }
        } finally {
            //解锁
            rLock.unlock();
        }
    }

2.3 验证库存、锁定库存、解锁库存sql语句

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.gao.sdyx.product.mapper.SkuInfoMapper">

    <resultMap id="skuInfoMap" type="com.gao.sdyx.model.product.SkuInfo" autoMapping="true"></resultMap>

    <!--//验证库存-->
    <select id="checkStock" resultMap="skuInfoMap">
        select
            id,category_id,sku_type,sku_name,img_url,per_limit,publish_status,
            check_status,is_new_person,sort,sku_code,price,market_price,stock,
            lock_stock,low_stock,sale,ware_id,create_time,update_time,is_deleted
        from sku_info
        where id = #{skuId} and stock-lock_stock > #{skuNum} for update
    </select>

    <!--//锁定库存:update-->
    <update id="lockStock">
        update sku_info set lock_stock = lock_stock + #{skuNum} where id = #{skuId}
    </update>

    <!--//解锁库存-->
    <update id="unlockStock">
        update sku_info set lock_stock = lock_stock - #{skuNum} where id = #{skuId}
    </update>

    <!--减库存-->
    <update id="minusStock">
        update sku_info set stock = stock - #{skuNum},lock_stock = lock_stock - #{skuNum},
                            sale = sale + #{skuNum} where id=#{skuId}
    </update>
</mapper>

2.4 下单过程,向订单表和订单项表两表中添加数据(保证事务的原子性)

    //1 向两张表添加数据
    // order_info 和 order_item
    /**
     * 保存订单内容,向表中添加数据
     * @param orderParamVo 提交的订单基本信息
     * @param cartInfoList 当前用户购物车商品(选中的购物项)
     * @return 订单id
     */
    @Transactional(rollbackFor = {Exception.class})
    public Long saveOrder(OrderSubmitVo orderParamVo, List<CartInfo> cartInfoList) {
        if(CollectionUtils.isEmpty(cartInfoList)) {
            throw new SdyxException(ResultCodeEnum.DATA_ERROR);
        }
        //查询用户提货点和团长信息
        Long userId = AuthContextHolder.getUserId();
        LeaderAddressVo leaderAddressVo = userFeignClient.getUserAddressByUserId(userId);
        if(leaderAddressVo == null) {
            throw new SdyxException(ResultCodeEnum.DATA_ERROR);
        }
        //计算金额
        //分摊后营销活动减少的金额
        Map<String, BigDecimal> activitySplitAmount = this.computeActivitySplitAmount(cartInfoList);
        //分摊后优惠卷减少的金额
        Map<String, BigDecimal> couponInfoSplitAmount = this.computeCouponInfoSplitAmount(cartInfoList, orderParamVo.getCouponId());

        //封装订单项数据
        List<OrderItem> orderItemList = new ArrayList<>();
        for(CartInfo cartInfo:cartInfoList) {
            OrderItem orderItem = new OrderItem();
            orderItem.setId(null); //订单项id
            orderItem.setCategoryId(cartInfo.getCategoryId()); //订单项商品所属分类
            if(cartInfo.getSkuType() == SkuType.COMMON.getCode()) {
                orderItem.setSkuType(SkuType.COMMON); //商品类型
            } else {
                orderItem.setSkuType(SkuType.SECKILL);
            }
            orderItem.setSkuId(cartInfo.getSkuId()); //订单项中商品skuId
            orderItem.setSkuName(cartInfo.getSkuName()); //商品名称
            orderItem.setSkuPrice(cartInfo.getCartPrice()); //商品单价
            orderItem.setImgUrl(cartInfo.getImgUrl()); //图片
            orderItem.setSkuNum(cartInfo.getSkuNum()); //数量
            orderItem.setLeaderId(orderParamVo.getLeaderId()); //团长id
            //营销活动金额
            BigDecimal activityAmount =
                    activitySplitAmount.get("activity:" + orderItem.getSkuId());
            if(activityAmount == null) {
                activityAmount = new BigDecimal(0);
            }
            orderItem.setSplitActivityAmount(activityAmount); //设置订单中每个商品参与活动分摊减少的金额

            //优惠卷金额
            BigDecimal couponAmount = couponInfoSplitAmount.get("coupon:" + orderItem.getSkuId());
            if(couponAmount == null) {
                couponAmount = new BigDecimal(0);
            }
            orderItem.setSplitCouponAmount(couponAmount); //设置订单中每个商品参与优惠券后分摊减少的金额

            //总金额
            BigDecimal skuTotalAmount =
                    orderItem.getSkuPrice().multiply(new BigDecimal(orderItem.getSkuNum()));
            //优惠之后金额
            BigDecimal splitTotalAmount =
                    skuTotalAmount.subtract(activityAmount).subtract(couponAmount);
            orderItem.setSplitTotalAmount(splitTotalAmount); //每个订单项分摊优惠之后的金额
            orderItemList.add(orderItem);
        }

        //封装订单OrderInfo数据
        OrderInfo orderInfo = new OrderInfo();
        orderInfo.setUserId(userId); //用户id
        orderInfo.setOrderNo(orderParamVo.getOrderNo()); //订单号 唯一标识
        orderInfo.setCouponId(orderParamVo.getCouponId()); //下单使用的优惠券id
        orderInfo.setOrderStatus(OrderStatus.UNPAID); //订单状态,生成成功未支付
        orderInfo.setLeaderId(orderParamVo.getLeaderId()); //团长id
        orderInfo.setLeaderName(leaderAddressVo.getLeaderName()); //团长名称

        orderInfo.setLeaderPhone(leaderAddressVo.getLeaderPhone()); //团长手机号
        orderInfo.setTakeName(leaderAddressVo.getTakeName()); //提货点名称
        orderInfo.setReceiverName(orderParamVo.getReceiverName()); //收货人姓名
        orderInfo.setReceiverPhone(orderParamVo.getReceiverPhone()); //收货人手机号
        orderInfo.setReceiverProvince(leaderAddressVo.getProvince()); //收货人省份(与团长在同一个区域)
        orderInfo.setReceiverCity(leaderAddressVo.getCity()); //城市
        orderInfo.setReceiverDistrict(leaderAddressVo.getDistrict()); //区
        orderInfo.setReceiverAddress(leaderAddressVo.getDetailAddress()); //详细地址
        orderInfo.setWareId(cartInfoList.get(0).getWareId()); //仓库id
        orderInfo.setProcessStatus(ProcessStatus.UNPAID); //设置订单状态为 未支付状态

        //计算订单原始金额
        BigDecimal originalTotalAmount = this.computeTotalAmount(cartInfoList);
        BigDecimal activityAmount = activitySplitAmount.get("activity:total");

        if(null == activityAmount) activityAmount = new BigDecimal(0);
        BigDecimal couponAmount = couponInfoSplitAmount.get("coupon:total");

        if(null == couponAmount) couponAmount = new BigDecimal(0);
        BigDecimal totalAmount = originalTotalAmount.subtract(activityAmount).subtract(couponAmount);
        //计算订单金额
        orderInfo.setOriginalTotalAmount(originalTotalAmount); //设置订单原始金额
        orderInfo.setActivityAmount(activityAmount); //设置活动减小金额
        orderInfo.setCouponAmount(couponAmount); //优惠券减少金额
        orderInfo.setTotalAmount(totalAmount); //所有优惠后总金额

        //计算团长佣金
        BigDecimal profitRate = new BigDecimal(0); //orderSetService.getProfitRate();
        BigDecimal commissionAmount = orderInfo.getTotalAmount().multiply(profitRate);
        orderInfo.setCommissionAmount(commissionAmount);

        //添加数据到订单基本信息表
        baseMapper.insert(orderInfo);

        //添加订单里面订单项
        orderItemList.forEach(orderItem -> {
            orderItem.setOrderId(orderInfo.getId()); //为每个订单项设置订单id字段
            orderItemMapper.insert(orderItem);
        });

        //如果当前订单使用优惠卷,更新优惠卷状态
        if(orderInfo.getCouponId() != null) {
            activityFeignClient.updateCouponInfoUseStatus(orderInfo.getCouponId(), userId, orderInfo.getId());
        }

        //下单成功,记录用户购物商品数量到redis
        //hash类型   key(userId)  -  field(skuId) - value(skuNum)
        String orderSkuKey = RedisConst.ORDER_SKU_MAP + orderParamVo.getUserId();
        BoundHashOperations<String, String, Integer> hashOperations = redisTemplate.boundHashOps(orderSkuKey);
        cartInfoList.forEach(cartInfo -> {
            if(hashOperations.hasKey(cartInfo.getSkuId().toString())) {
                Integer orderSkuNum = hashOperations.get(cartInfo.getSkuId().toString()) + cartInfo.getSkuNum();
                hashOperations.put(cartInfo.getSkuId().toString(), orderSkuNum);
            }
        });
        redisTemplate.expire(orderSkuKey, DateUtil.getCurrentExpireTimes(), TimeUnit.SECONDS);

        //订单id
        return orderInfo.getId();
    }

2.5 下单完成,通过mq异步方式删除该用户购物车本次选中的购物数据(之前用户购物车数据存在redis中,使用hash类型存储,键key表示用户id,值为(skuId,skuInfo))

2.5.1 往购物车中添加数据流程(下单过程不涉及此步骤,只是为了对比下单完整删除购物车数据)

/**
     * 添加商品到购物车
     * @param userId
     * @param skuId
     * @param skuNum
     */
    @Override
    public void addToCart(Long userId, Long skuId, Integer skuNum) {
        //1 因为购物车数据存储到redis里面,
        // 从redis里面根据key获取数据,这个key包含userId(区分不同用户的购物车)
        String cartKey = this.getCartKey(userId);
        //redis中存储的格式为:userId, skuId, 购物车sku数据对象
        BoundHashOperations<String, String, CartInfo> hashOperations =
                redisTemplate.boundHashOps(cartKey);
        //2 根据第一步查询出来的结果,得到是skuId + skuNum关系
        CartInfo cartInfo = null;
        // 目的:判断是否是第一次添加这个商品到购物车
        // 进行判断,判断结果里面,是否有skuId
        if(hashOperations.hasKey(skuId.toString())) {
            //3 如果结果里面包含skuId,不是第一次添加
            //3.1 根据skuId,获取对应数量,更新数量
            cartInfo = hashOperations.get(skuId.toString());
            //把购物车存在商品之前数量获取数量,在进行数量更新操作
            Integer currentSkuNum = cartInfo.getSkuNum() + skuNum;
            if(currentSkuNum < 1) {
                return;
            }

            //更新cartInfo对象
            cartInfo.setSkuNum(currentSkuNum);
            cartInfo.setCurrentBuyNum(currentSkuNum);

            //判断商品数量不能大于限购数量
            Integer perLimit = cartInfo.getPerLimit();
            if(currentSkuNum > perLimit) {
                throw new SdyxException(ResultCodeEnum.SKU_LIMIT_ERROR);
            }

            //更新其他值
            cartInfo.setIsChecked(1);
            cartInfo.setUpdateTime(new Date());
        } else {
            //4 如果结果里面没有skuId,就是第一次添加
            //4.1 直接添加
            skuNum = 1;

            //远程调用根据skuId获取skuInfo
            SkuInfo skuInfo = productFeignClient.getSkuInfo(skuId);
            if(skuInfo == null) {
                throw new SdyxException(ResultCodeEnum.DATA_ERROR);
            }

            //封装cartInfo对象
            cartInfo = new CartInfo();
            cartInfo.setSkuId(skuId);
            cartInfo.setCategoryId(skuInfo.getCategoryId());
            cartInfo.setSkuType(skuInfo.getSkuType());
            cartInfo.setIsNewPerson(skuInfo.getIsNewPerson());
            cartInfo.setUserId(userId);
            cartInfo.setCartPrice(skuInfo.getPrice());
            cartInfo.setSkuNum(skuNum);
            cartInfo.setCurrentBuyNum(skuNum);
            cartInfo.setSkuType(SkuType.COMMON.getCode());
            cartInfo.setPerLimit(skuInfo.getPerLimit());
            cartInfo.setImgUrl(skuInfo.getImgUrl());
            cartInfo.setSkuName(skuInfo.getSkuName());
            cartInfo.setWareId(skuInfo.getWareId());
            cartInfo.setIsChecked(1);
            cartInfo.setStatus(1);
            cartInfo.setCreateTime(new Date());
            cartInfo.setUpdateTime(new Date());
        }

        //5 更新redis缓存
        hashOperations.put(skuId.toString(), cartInfo);

        //6 设置有效时间
        this.setCartKeyExpire(cartKey);
    }

2.5.2 下单完成,删除选中的购物车数据(生产者发送mq消息)

//下单完成,删除购物车记录
        //发送mq消息(交换机、路由键、消息)
        rabbitService.sendMessage(MqConst.EXCHANGE_ORDER_DIRECT, MqConst.ROUTING_DELETE_CART, orderParamVo.getUserId());

2.5.3 消费者接收mq消息

package com.gao.sdyx.cart.receiver;

import com.gao.sdyx.cart.service.CartInfoService;
import com.gao.sdyx.mq.constant.MqConst;
import com.rabbitmq.client.Channel;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.Exchange;
import org.springframework.amqp.rabbit.annotation.Queue;
import org.springframework.amqp.rabbit.annotation.QueueBinding;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.io.IOException;

@Component
public class CartReceiver {

    @Autowired
    private CartInfoService cartInfoService;

    /**
     * 下单完成,通过mq异步方式删除购物车中本地下单的商品(购物车中选中的数据)
     * 下单完整后 消费者端从mq根据路由键从消息队列中接收消息
     * @param userId
     * @param message
     * @param channel
     * @throws IOException
     */
    @RabbitListener(bindings = @QueueBinding(
            value = @Queue(value = MqConst.QUEUE_DELETE_CART, durable = "true"),
            exchange = @Exchange(value = MqConst.EXCHANGE_ORDER_DIRECT),
            key = {MqConst.ROUTING_DELETE_CART}
    ))
    public void deleteCart(Long userId, Message message, Channel channel) throws IOException {
        if(userId != null) {
            cartInfoService.deleteCartChecked(userId);
        }
        //手动确认
        channel.basicAck(message.getMessageProperties().getDeliveryTag(),false);
    }
}

2.5.4 根据userId删除选中的购物数据

//获取当前用户购物车选中购物项
    @Override
    public List<CartInfo> getCartCheckedList(Long userId) {
        String cartKey = this.getCartKey(userId);
        BoundHashOperations<String,String,CartInfo> boundHashOperations =
                redisTemplate.boundHashOps(cartKey);
        List<CartInfo> cartInfoList = boundHashOperations.values();
        //isChecked = 1购物项选中
        List<CartInfo> cartInfoListNew = cartInfoList.stream()
                .filter(cartInfo -> {
                    return cartInfo.getIsChecked().intValue() == 1;
                }).collect(Collectors.toList());
        return cartInfoListNew;
    }

    //根据userId删除选中购物车记录
    @Override
    public void deleteCartChecked(Long userId) {
        //根据userid查询选中购物车记录
        List<CartInfo> cartInfoList = this.getCartCheckedList(userId);

        //查询list数据处理,得到skuId集合
        List<Long> skuIdList = cartInfoList.stream().map(item -> item.getSkuId()).collect(Collectors.toList());

        //构建redis的key值
        // hash类型 key filed-value
        String cartKey = this.getCartKey(userId);

        //根据key查询filed-value结构
        BoundHashOperations<String,String,CartInfo> hashOperations =
                redisTemplate.boundHashOps(cartKey);

        //根据filed(skuId)删除redis数据
        skuIdList.forEach(skuId -> {
            hashOperations.delete(skuId.toString());
        });
    }

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
概要介绍: 本课程主要是介绍并实战一款java中间件~redisson,介绍redisson相关的核心技术栈及其典型的应用场景,其中的应用场景就包括布隆过滤器、限流器、短信发送、实时/定时邮件发送、数据字典、分布式服务调度等等,在业界号称是在java项目里正确使用redis的姿势。本课程的目标就在于带领各位小伙伴一起学习、攻克redisson,更好地巩固自己的核心竞争力,而至于跳槽涨薪,自然不在话下!  课程内容: 说起redisson,可能大伙儿不是很熟悉,但如果说起redis,想必肯定很多人都晓得。没错,这家伙字如其名,它就是架设在redis基础上的一款综合性的、新型的中间件,号称是java企业级应用开发中正确使用redis的姿势/客户端实例。 它是架设在redis基础之上,但拥有的功能却远远多于原生Redis 所提供的,比如分布式对象、分布式集合体系、分布式以及分布式服务调度等一系列具有分布式特性的对象实例… 而这些东西debug将在本门课程进行淋漓尽致的介绍并实战,除此之外,我们将基于spring boot2.0搭建的多模块项目实战典型的应用场景:对象存储、数据字典、短信发送、实时/定时邮件发送、布隆过滤器、限流组件、分布式服务调度....课程大纲如下所示: 下面罗列一下比较典型的核心技术栈及其实际业务场景的实战,如下图所示为redisson基于订阅-发布模式的核心技术~主题Topic的实际业务场景,即实时发送邮件: 而下图则是基于“多值映射MultiMap”数据结构实战实现的关于“数据字典”的缓存管理: 除此之外,我们还讲解了可以与分布式服务调度中间件dubbo相媲美的功能:分布式远程服务调度,在课程中我们动手搭建了两个项目,用于分别充当“生产者”与“消费者”角色,最终通过redisson的“服务调度组件”实现服务与服务之间、接口与接口之间的调用!  课程收益: (1)认识并掌握redisson为何物、常见的几种典型数据结构-分布式对象、集合、服务的应用及其典型应用场景的实战; (2)掌握如何基于spring boot2.0整合redisson搭建企业级多模块项目,并以此为奠基,实战企业级应用系统中常见的业务场景,巩固相应的技术栈! (3)站在项目管理与技术精进的角度,掌握对于给定的功能模块进行业务流程图的绘制、分析、模块划分、代码实战与性能测试和改进,提高编码能力与其他软实力; (4)对于Java微服务、分布式、springboot精进者而言,学完本课程,不仅可以巩固提高中间件的实战能力,其典型的应用场景更有助于面试、助力相关知识点的扫盲! 如下图所示: 关键字:Spring Boot,Redis,缓存穿透,缓存击穿,缓存雪崩,红包系统,Mybatis,高并发,多线程并发编程,发送邮件,列表List,集合Set,排行榜,有序集合SortedSet,哈希Hash ,进阶实战,面试,微服务、分布式 适用人群:redisson学习者,分布式中间件实战者,微服务学习者,java学习者,spring boot进阶实战者,redis进阶实战者

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值