高并发环境下频繁更改购物车中的商品数量的实现思路及部分代码实现(只对购物车中的商品数量做缓存)——redis做缓存mq将redis中修改的数据同步到数据库

电商系统中,为解决购物车商品数量在高并发环境下的频繁更改问题,采用Redis作为缓存,结合MQ消息队列实现Redis与MySQL数据库的数据同步。当Redis中购物车商品数量发生变化时,通过MQ通知数据库进行更新,有效减轻系统压力。购物车商品的增删及数量调整都在Redis中操作,查询时先查数据库,再查Redis,最后更新商品数量。

电商、外卖、直播等平台基本上都有购物车的功能。
购物车的作用:
1.需要购物的商品的保存
2.购物车可以充当收藏
购物车都需要设置商品的上限

购物车需要接口
1.查询登录用户的购物车列表数据
2.商品详情页、商品列表页 可以加入购物车
3.购物车列表页 可以实现商品数量的变化:增加、减少

实现思路
1.直接操作数据库
用的比较多 如果数据量大或者并发量大的 就会对系统很大压力
加减直接操作数据库
2.使用Redis+Mysql
1.直接对购物车表做缓存
Redis 做购物车的缓存,后面的操作都操作Redis ,最终借助MQ实现Redis数据和Mysql数据的同步
Hash: key:micro:cart:uid 字段:商品的skuid 值:购物车详情信息 有效期:30分钟
只要Redis发送变化发送MQ消息,实现Mysql数据的同步
2.只对购物车中的商品数据做缓存
Hash: key:micro:cart:uid 字段:商品的skuid 值:数量
数量变化 发送MQ消息
购物车商品新增 操作Mysql 可以直接操作Redis
查询购物车列表的时候:先查询数据库,再查询Redis,最后更新商品数量

代码实现

package com.lxm.productservice.service.impl;

import com.alibaba.fastjson.JSON;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.Date;
import java.util.List;
import java.util.Map;

/**
 * @Author LXM
 * @Date 2020/7/16 0016
 */
@Service
public class OmsCarItemServiceImpl implements OmsCarItemService {
    @Resource
    private OmsCarItemDao dao;
    @Resource
    private RedissionCore redissionCore;
    @Resource
    private RabbitTemplate rabbitTemplate;
    /**
     * 向购物车表中添加数据
     * @param token
     * @param dto
     * @return
     */
    @Override
    public R addItem(String token, CartProductDto dto) {
        //获取redis缓存中的token
        String json=redissionCore.getStr(RedisKeyConfig.AUTH_TOKEN+token);
        //校验令牌是否失效
        if (json!=null&&json.length()>0){
            //将token转化为用户对象
            UmsUser umsUser= JSON.parseObject(json,UmsUser.class);
            //创建购物车对象
            OmsCartItem item=new OmsCartItem((long)dto.getPid(),(long)dto.getPskuid(),umsUser.getId(),dto.getCount(),dto.getPrice(),dto.getPicurl(),dto.getPname(),(long)dto.getPtype());
            //查询购物车表中是否添加过这个商品,查询购物车表中这个商品的商品数量
            Integer c=dao.queryById(umsUser.getId(),dto.getPskuid());
            if (c!=null){
                //如果添加过,就修改这个表中的商品数量
                CartCountDto cartCountDto=new CartCountDto();
                cartCountDto.setCount(c+dto.getCount());
                cartCountDto.setPskuid(dto.getPskuid());
                cartCountDto.setUid(umsUser.getId());
                //修改数据库中的商品数量
                if (dao.changeCount(cartCountDto)>0){
                    //修改成功后将商品数量更新到缓存redis中
                    redissionCore.addMap(RedisKeyConfig.CAR_ITEM_PRODUCT_NUM+umsUser.getId(),dto.getPskuid()+"",c+dto.getCount());
                }
            }else {
                //如果没有添加过,向数据库中添加数据
                if(dao.insert(dto)>0){
                    //添加成功后,将商品数量添加到redis缓存中
                    redissionCore.addMap(RedisKeyConfig.CAR_ITEM_PRODUCT_NUM+umsUser.getId(),dto.getPskuid()+"",dto.getCount());
                }
            }
            return RUtil.ok();
        }
        return RUtil.error("令牌失效,请重新登陆");
    }

    /**
     * 查询购物车表中的商品
     * @param token
     * @return
     */
    @Override
    public R queryCar(String token) {
        //获取redis缓存中的token
        String json=redissionCore.getStr(RedisKeyConfig.AUTH_TOKEN+token);
        //校验令牌是否有效
        if (json!=null&&json.length()>0){
            UmsUser umsUser=JSON.parseObject(json,UmsUser.class);
            //查询当前用户购物车表中的商品信息
            List<OmsCartItem> itemList=dao.querylist(umsUser.getId());
            //查询redis中该用户的购物车商品数量信息
            Map<Object,Object> map=redissionCore.getMap(RedisKeyConfig.CAR_ITEM_PRODUCT_NUM+umsUser.getId());
            //对从数据库查询的结果进行遍历,防止出现数据库商品数量和redis缓存中商品数量不一致的情况
            for (OmsCartItem o:itemList){
                long l=(long)map.get(o.getProductSkuId());
                if (l!=o.getQuantity()){
                    o.setQuantity((int)l);
                }
            }
            return RUtil.ok(itemList);
        }
        return RUtil.error("令牌失效,请重新登陆");
    }

    /**
     * 修改购物车表中的商品数量
     * @param token
     * @param dto
     * @return
     */
    @Override
    public R changeCount(String token, CartCountDto dto) {
        String json=redissionCore.getStr(RedisKeyConfig.AUTH_TOKEN+token);
        if (json!=null&&json.length()>0){
            UmsUser umsUser=JSON.parseObject(json,UmsUser.class);
            //判断修改商品数量的类型,1添加商品数量  2减少商品数量
            if (dto.getType()==2){
                dto.setCount(-dto.getCount());
            }
            dto.setUid(umsUser.getId());
            //获取原来redis中存储的商品数量的值
            long c=Long.parseLong(redissionCore.getMap(RedisKeyConfig.CAR_ITEM_PRODUCT_NUM+umsUser.getId(),dto.getPskuid()+""));
            //修改redis中存储的商品数量的值
            redissionCore.addMap(RedisKeyConfig.CAR_ITEM_PRODUCT_NUM+umsUser.getId(),dto.getPskuid()+"",c+dto.getCount());
            //将修改的商品数量信息同步到消息队列中,消息队列将信息更改到数据库中
            MqMessageDto mqMessageDto=new MqMessageDto(IdGeneratorSingle.getInstance().getId(),2, new Date(),JSON.toJSONString(dto));
            rabbitTemplate.convertAndSend("micro:car:skucount",null,mqMessageDto);
            return RUtil.ok();
        }
        return RUtil.error("令牌失效,请重新登陆");
    }
}
package com.lxm.productservice.dao;

import com.lxm.common.dto.CartCountDto;
import com.lxm.common.dto.CartProductDto;
import com.lxm.entity.car.OmsCartItem;

import java.util.List;

public interface OmsCarItemDao {
    /**
     * 查询购物车表中商品的数量
     * @param id
     * @param pskuid
     * @return
     */
    Integer queryById(Long id, int pskuid);

    /**
     * 修改购物车表中的商品数量
     * @param cartCountDto
     * @return
     */
    Integer changeCount(CartCountDto cartCountDto);

    /**
     * 向购物车表中添加数据
     * @param dto
     * @return
     */
    Integer insert(CartProductDto dto);

    /**
     * 查询用户添加到购物车表的商品信息
     * @param id
     * @return
     */
    List<OmsCartItem> querylist(Long id);
}

同步代码

@Configuration
public class RabbitMqConfig {
    
    @Bean
    public Queue createCarSkuCount(){
        return new Queue("micro:car:skucount");
    }
}
package com.lxm.productservice.listener;

import com.alibaba.fastjson.JSON;
import com.lxm.common.dto.CartCountDto;
import com.lxm.common.dto.MqMessageDto;
import com.lxm.common.utils.RedissionCore;
import com.lxm.productservice.dao.OmsCarItemDao;
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;

/**
 * @Author LXM
 * @Date 2020/7/16 0016
 */
@Component
@RabbitListener(queues = "micro:car:skucount")
public class OmsCarItemListener {
    @Resource
    private OmsCarItemDao dao;


    /**
     * 监听队列中的消息,如果redis中修改了商品的数量,将修改信息发送到该队列中,然后再将消息同步到数据库中
     * @param dto
     */
    @RabbitHandler
    public void handler(MqMessageDto dto){
        if (dto != null){
            if (dto.getType()==2){
                String json=dto.getMsg().toString();
                dao.changeCount(JSON.parseObject(json, CartCountDto.class));
            }
        }
    }
}

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值