电商、外卖、直播等平台基本上都有购物车的功能。
购物车的作用:
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));
}
}
}
}
电商系统中,为解决购物车商品数量在高并发环境下的频繁更改问题,采用Redis作为缓存,结合MQ消息队列实现Redis与MySQL数据库的数据同步。当Redis中购物车商品数量发生变化时,通过MQ通知数据库进行更新,有效减轻系统压力。购物车商品的增删及数量调整都在Redis中操作,查询时先查数据库,再查Redis,最后更新商品数量。

被折叠的 条评论
为什么被折叠?



