MySQL, Oracle, Linux, 软件架构及大数据技术知识分享平台

网站首页 > 精选文章 / 正文

Redis 实现购物车(附源码)

2024-12-03 15:22 huorong 精选文章 7 ℃ 0 评论

写在前面

Redis 是完全开源的,遵守 BSD 协议,是一个高性能的 key-value 数据库。 Redis 与其他 key - value 缓存产品有以下三个特点:

Redis支持数据的持久化,可以将内存中的数据保存在磁盘中,重启的时候可以再次加载进行使用。Redis不仅仅支持简单的key-value类型的数据,同时还提供string、list、set、zset、hash五种数据结构的存储。Redis支持数据的备份,即master-slave模式的数据备份。

使用Redis做购物车存储好处有两点:

无需操作数据库,当访问量比较大时,高速读写数据库,对数据库压力比较大。Redis性能好,并发高。

一、 设计思想

使用Redis来实现购物车功能第一个要解决的问题就是Key的问题。需要我们来判断一对多关系中,谁是唯一谁就是Key。对于购物车来说用户就是唯一,那么就可以使用用户主键来作为购车的Key:项目名:模块名:用户主键,如:WHALE:CART:334522354345。第二个要解决的问题就是,我们要存什么东西,这里有两种方案:

  • 半持久化:直接存店铺id+商品Id作为购物车项Key,前端先查redis获取商品清单ids,然后根据ids异步查询具体数据。优点是如果商品价格改了,前端能够实时知道商品的价格。缺点适应是场景少,对数据库有一定的压力。如果商品只有SKU还好,如果商品还有一些其他属性时,当用户选择商品,选择商品属性时,后台是没有记录用户选了那些属性的。解决方案是把属性Id也加到Key中并且缓存起来,查询时和商品id作为参数查询具体的购物车项的明细。
  • 不持久化:将购物车项的所有必要信息作为值存到Redis中,根据用户购物车Key就可以获取购物车商品集合。优点是性能高,速度快,不操作数据库。缺点是如果商品价格修改了,redis中的商品价格还是未改之前的,商品价格不能同步。也就是缓存中的信息和数据库中的信息会有不同步的情况。解决方案是添加购车时将SKU的id作为Key,价格作为值缓存起来,如果属性包含价格也需要将属性的Id作为Key,价格作为值缓存起来。如果SKU或者属性价格有修改则在修改方法中如果Redis中存在该SKU或属性则更新Redis中对应的数据,微服务架构可以通过消息队列更新Redis中的价格。查询购物车时商品价格根据SKU和属性价格计算出来返回给前端。

二、 购物车时序图

三、代码示例

BaseEntity.class:实体父类

@MappedSuperclass
public class BaseEntity<ID> implements Serializable {
    private static final long serialVersionUID = 3087254371468631854L;
    @Id
    @JsonSerialize(
        using = ToStringSerializer.class
    )
    private ID id;
    private Integer status;
    @JsonDeserialize(
        using = LocalDateTimeDeserializer.class
    )
    @JsonSerialize(
        using = LocalDateTimeSerializer.class
    )
    private LocalDateTime createTime;
    @JsonDeserialize(
        using = LocalDateTimeDeserializer.class
    )
    @JsonSerialize(
        using = LocalDateTimeSerializer.class
    )
    private LocalDateTime updateTime;

    public BaseEntity() {
    }

    public ID getId() {
        return this.id;
    }

    public void setId(ID id) {
        this.id = id;
    }

    public Integer getStatus() {
        return this.status;
    }

    public void setStatus(Integer status) {
        this.status = status;
    }

    public LocalDateTime getCreateTime() {
        return this.createTime;
    }

    public void setCreateTime(LocalDateTime createTime) {
        this.createTime = createTime;
    }

    public LocalDateTime getUpdateTime() {
        return this.updateTime;
    }

    public void setUpdateTime(LocalDateTime updateTime) {
        this.updateTime = updateTime;
    }

    public String toString() {
        return "BaseEntity{id=" + this.id + ", status=" + this.status + ", createTime=" + this.createTime + ", updateTime=" + this.updateTime + '}';
    }
}

Car.class:购物车实体类

@Data
public class Cart {

    @ApiModelProperty(value = "购物车项Id")
    private String cartItemId;

    @ApiModelProperty(value = "商品Id", required = true)
    @NotNull(message = "productId不能为空")
    @JsonSerialize(using = ToStringSerializer.class)
    private Long productId;

    @ApiModelProperty(value = "skuId", required = true)
    @NotNull(message = "skuId不能为空")
    @JsonSerialize(using = ToStringSerializer.class)
    private Long skuId;

    @ApiModelProperty(value = "skuPrice", required = true)
    @NotNull(message = "sku售价不能为空")
    @JsonSerialize(using = ToStringSerializer.class)
    private BigDecimal skuPrice;


    @ApiModelProperty(value = "discountSkuPrice", required = true)
    @JsonSerialize(using = ToStringSerializer.class)
    private BigDecimal discountSkuPrice;


    @ApiModelProperty(value = "购买数量", required = true, example = "1")
    @NotNull(message = "购买数量不能为空")
    private Long quantity;

    @ApiModelProperty(value = "商品名", required = true)
    @NotBlank(message = "商品名")
    private String name;

    @ApiModelProperty(value = "商品图片url", required = true)
    @NotBlank(message = "商品图片url")
    private String images;

    @ApiModelProperty(value = "售价", required = true)
    @NotNull(message = "商品价格不能为空")
    private BigDecimal price;

    @ApiModelProperty(value = "打包费", required = false)
    private BigDecimal packingFee;

    @ApiModelProperty(value = "折扣价", required = true)
    private BigDecimal discountPrice;

    @ApiModelProperty(value = "是否勾选", required = true)
    private Boolean check;

    @ApiModelProperty(value = "购买的商品列表", required = true)
    @NotEmpty(message = "购买的商品属性列表不能为空")
    private List<ProductProperty> propertys;

    @ApiModelProperty(value = "商品属性值", required = true)
    @NotBlank(message = "商品属性值不能为空")
    private String propValues;

    @ApiModelProperty(value = "商品子标题", required = true)
    private String subtitle;

    @ApiModelProperty(value = "是否可以外带", required = true)
    private String canTakeout;

    @ApiModelProperty(value = "门店id")
    @NotNull(message = "门店id不能为空")
    @JsonSerialize(using = ToStringSerializer.class)
    private Long shopId;
}

ProductProperty.class:商品属性类

@Data
@Entity
public class ProductProperty extends BaseEntity<Long> implements Comparable<ProductProperty>, Serializable {

    @ApiModelProperty(value = "商品id")
    @JsonSerialize(using = ToStringSerializer.class)
    private Long productId;

    @ApiModelProperty(value = "属性名id")
    @JsonSerialize(using = ToStringSerializer.class)
    private Long propId;

    @ApiModelProperty(value = "属性名")
    private String propName;

    @ApiModelProperty(value = "属性类型")
    private Integer rule;

    @ApiModelProperty(value = "属性值")
    private String propValue;

    @ApiModelProperty(value = "属性值id")
    @JsonSerialize(using = ToStringSerializer.class)
    private Long propValueId;

    @ApiModelProperty(value = "额外价格")
    private BigDecimal price;

    @ApiModelProperty(value = "顺序索引")
    private Integer sequence;

    @ApiModelProperty(value = "组序列")
    private Integer groupSequence;

    @ApiModelProperty(value = "显示状态 1:显示 0:隐藏")
    private Integer visible = 1;

    @Override
    public int compareTo(ProductProperty p2) {
        return Comparator.comparing(ProductProperty::getRule)
                .thenComparing(ProductProperty::getGroupSequence)
                .thenComparing(ProductProperty::getSequence)
                .compare(this, p2);
    }

    public static boolean isDeletedOrHidden(ProductProperty productProperty) {
        return productProperty.getStatus().equals(DataStatus.DELETED.getStatus()) ||
                productProperty.getVisible() == 0;
    }
}

CarController.class:Controller类

@Slf4j
@RestController
@AllArgsConstructor
@Api(value = "ECCart", tags = {"【EC购物车】- ECCart"})
public class EcCartController {

    private static final String MINI_URL_PREFIX = UrlConstant.URL_EC_API_PREFIX + "cart";

    private final CartService cartService;
    private final ProductSkuService productSkuService;
    private final ProductService productService;

    /**
     * 查询我的购物车
     * @return
     */
    @ApiOperation(value = "查询我的购物车")
    @PostMapping(value = MINI_URL_PREFIX + "/list")
    public Response<List<Cart>> queryCarts(@RequestBody Cart dto){
        if(Objects.isNull(dto.getShopId())){
            return ResponseUtils.error(1, "请选择门店");
        }
        return ResponseUtils.success(cartService.queryCarts(RequestUserHolder.getUserId(),dto.getShopId()));
    }

    /**
     * 添加到购物车
     * @param dto
     * @return
     */
    @ApiOperation(value = "添加到购物车")
    @PostMapping(value = MINI_URL_PREFIX + "/add")
    public Response<Boolean> addCart(@RequestBody Cart dto) {
        // 查询是否删除
        long pscount = productService.findByIdAndStatus(dto.getProductId());
        if(pscount > 0){
            return ResponseUtils.error(1, "商品不存在");
        }
        // 查询是否下架
        long pvcount = productService.findByIdAndVisible(dto.getProductId());
        if(pvcount > 0){
            return ResponseUtils.error(1, "商品已下架");
        }
        // 查询库存
        long count = productSkuService.findBySkuIdAndStatus(dto.getSkuId());
        // 判断是否有无库存
        if(count == 0) {
            return ResponseUtils.error(1, "暂无库存");
        }
        return cartService.addCart(dto, RequestUserHolder.getUserId());
    }

    /**
     * 添加到购物车
     * @param dto
     * @return
     */
    @ApiOperation(value = "批量添加到购物车")
    @PostMapping(value = MINI_URL_PREFIX + "/batch/add")
    public Response batchAddCart(@RequestBody CartDto dto) {
        Long shopId = dto.getShopId();
        List<Cart> carts = new ArrayList<>();
        try {
            for (Cart cart : dto.getCarts()) {
                // 传递shopId
                cart.setShopId(shopId);
                // 查询库存
                long count = productSkuService.findBySkuIdAndStatus(cart.getSkuId());
                // 判断是否有无库存
                if(count == 0) {
                    carts.add(cart);
                    continue;
                }
                // 查询是否删除
                long pscount = productService.findByIdAndStatus(cart.getProductId());
                if(pscount > 0){
                    return ResponseUtils.error(1, "商品不存在");
                }
                // 查询是否下架
                long pvcount = productService.findByIdAndVisible(cart.getProductId());
                if(pvcount > 0){
                    return ResponseUtils.error(1, "商品已下架");
                }
                cartService.addCart(cart, RequestUserHolder.getUserId());
            }
            if(carts.size() > 0) {
                return ResponseUtils.success(carts);
            }else {
                return ResponseUtils.success();
            }
        }catch (Exception e) {
            e.printStackTrace();
        }
        return ResponseUtils.error(1, "添加购物车失败");
    }

    /**
     * 更新购物车
     * @param dto
     * @return
     */
    @ApiOperation(value = "更新购物车")
    @PostMapping(value = MINI_URL_PREFIX + "/update")
    public Response<Boolean> updateCart(@RequestBody Cart dto){
        return cartService.updateCart(dto, RequestUserHolder.getUserId());
    }

    /**
     * 删除购物车
     * @param cartDto
     * @return
     */
    @ApiOperation(value = "删除购物车商品", notes = "已选择要删除的商品列表")
    @PostMapping(value = MINI_URL_PREFIX + "/delete")
    public Response<Boolean> deleteCart(@RequestBody CartDto cartDto) {
        return cartService.deleteCart(cartDto.getCartIds(), RequestUserHolder.getUserId(),cartDto.getShopId());
    }

    /**
     * 删除购物车
     * @return
     */
    @ApiOperation(value = "删除购物车所有商品")
    @PostMapping(value = MINI_URL_PREFIX + "/delete/all")
    public Response<Boolean> deleteAllCart(@RequestBody CartDto cartDto) {
        return cartService.deleteAllCart(RequestUserHolder.getUserId(),cartDto.getShopId());
    }

}

CarService.class:购物车接口类

public interface CartService {
    /**
     * 查询我的购物车
     * @param userId
     * @return
     */
    List<Cart> queryCarts(Long userId,Long shopId);

    /**
     * 添加购物车
     * @param dto
     * @param userId
     * @return
     */
    Response<Boolean> addCart(Cart dto, Long userId);

    /**
     * 更新购物车
     * @param dto
     * @param userId
     * @return
     */
    Response<Boolean> updateCart(Cart dto, Long userId);

    /**
     * 删除购物车
     * @param cartIds
     * @param userId
     * @return
     */
    Response<Boolean> deleteCart(List<String> cartIds, Long userId,Long shopid);

    /**
     * 清空购物车
     * @param userId
     * @return
     */
    Response<Boolean> deleteAllCart(Long userId,Long shopId);
}

CarServiceImpl.class:购物车接口实现类

@Slf4j
@Service
@AllArgsConstructor
public class CartServiceImpl implements CartService {

    private final StringRedisTemplate redisTemplate;
    /**
     * 查询我的购物车
     * @param userId
     * @return
     */
    @Override
    public List<Cart> queryCarts(Long userId,Long shopId) {
        // 用户已登录,查询登录状态的购物车
        String key = CacheConstant.RL_CART + userId + ":" + shopId;
        // 获取登录状态的购物车
        BoundHashOperations<String, Object, Object> userIdOps = this.redisTemplate.boundHashOps(key);
        // 购物车数据
        List<Object> userCartJsonList = userIdOps.values();

        return userCartJsonList.stream().map(userCartJson-> {
            Cart cart = JSON.parseObject(userCartJson.toString(), Cart.class);
            // 查询单价价格
            String discountPrice = redisTemplate.opsForValue().get(CacheConstant.RL_DISCOUNT_SKU + cart.getSkuId());
            String price = redisTemplate.opsForValue().get(CacheConstant.RL_DISCOUNT_SKU + cart.getSkuId());
            BigDecimal propAmount =  cart.getPropertys().stream().map(item -> {
                String propPrice = redisTemplate.opsForValue().get(CacheConstant.RL_PROP + item.getId());
                return new BigDecimal(Objects.isNull(propPrice) ? "0" : propPrice);
            }).reduce(BigDecimal.ZERO, BigDecimal::add);
            // SKU 价格 + 属性价格
            BigDecimal discountTotal = propAmount.add(new BigDecimal(discountPrice));
            BigDecimal total = propAmount.add(new BigDecimal(price));
            // 单价 x 数量
            cart.setDiscountPrice(discountTotal);
            cart.setPrice(total);
            return cart;
        }).collect(Collectors.toList());
    }

    /**
     * 添加到购物车
     * @param dto
     * @return
     */
    @Override
    public Response<Boolean> addCart(Cart dto, Long userId) {
        try {
            // 用户已登录,查询登录状态的购物车
            String key = CacheConstant.RL_CART + userId + ":" + dto.getShopId();

            // 1. 组装购物车商品Key:商品Id + 排序后的属性Ids
            String pidsKey = dto.getPropertys().stream().map(ProductProperty::getId).sorted(Long::compareTo).map(Object::toString).collect(Collectors.joining("_"));
            String cartItemKey = dto.getProductId().toString() + ":" + pidsKey + ":" + dto.getSkuId().toString();
            // 缓存购物车项id
            dto.setCartItemId(cartItemKey);
            // 2. 查询用户购物车
            BoundHashOperations<String, Object, Object> hashOps = this.redisTemplate.boundHashOps(key);
            // 3. 判断购物车数据组是否已存在该商品
            if (hashOps.hasKey(cartItemKey)) {
                // 购物车已存在该记录,更新数量
                String cartJson = hashOps.get(cartItemKey).toString();
                Cart cart = JSON.parseObject(cartJson, Cart.class);
                dto.setQuantity(cart.getQuantity() + dto.getQuantity());
            }
            // 4. 将 SKU 价格写入 Redis
            // 售价
            redisTemplate.opsForValue().set(CacheConstant.RL_SKU + dto.getSkuId(), dto.getSkuPrice().toString());
            // 折扣价
            redisTemplate.opsForValue().set(CacheConstant.RL_DISCOUNT_SKU + dto.getSkuId(), Objects.isNull(dto.getDiscountSkuPrice()) ? dto.getSkuPrice().toString() : dto.getDiscountSkuPrice().toString());
            // 5. 将 属性 价格写入 Redis
            dto.getPropertys().forEach(item->
                redisTemplate.opsForValue().set(CacheConstant.RL_PROP + item.getId().toString(), item.getPrice().toString())
            );
            // 5. 将购物车记录写入 Redis
            hashOps.put(cartItemKey, JSON.toJSONString(dto));
            return ResponseUtils.success(Boolean.TRUE);
        } catch (Exception e){
            e.printStackTrace();
        }
        return ResponseUtils.error(1, "添加购物车失败");
    }

    /**
     * 更新购物车
     * @param dto
     * @param userId
     * @return
     */
    @Override
    public Response<Boolean> updateCart(Cart dto, Long userId) {
        try {

            // 判断购物车项id是否为空
            if(StringUtils.isBlank(dto.getCartItemId())){
                return ResponseUtils.error(1, "购物车项id为空");
            }

            // 用户已登录,查询登录状态的购物车
            String key = CacheConstant.RL_CART + userId + ":" + dto.getShopId();

            // 获取hash操作对象
            BoundHashOperations<String, Object, Object> hashOperations = this.redisTemplate.boundHashOps(key);

            // 商品Id + 排序后的属性Ids
//            String pidsKey = dto.getPropertys().stream().map(ProductProperty::getId).sorted(Long::compareTo).map(Object::toString).collect(Collectors.joining(":"));
//            String pidsKey = dto.getSkuId().toString();
//            String cartItemKey = dto.getProductId().toString() + ":" + pidsKey;

            if(hashOperations.hasKey(dto.getCartItemId())){
                // 获取购物车信息
                String cartJson = hashOperations.get(dto.getCartItemId()).toString();
                final long i = dto.getQuantity();
                final boolean check = dto.getCheck();
                dto = JSON.parseObject(cartJson, Cart.class);
                // 更新数量
                dto.setQuantity(i);
                // 更新选择状态
                dto.setCheck(check);
                // 写入redis
                hashOperations.put(dto.getCartItemId(), JSON.toJSONString(dto));
            }
            return ResponseUtils.success(Boolean.TRUE);
        } catch (Exception e){
            e.printStackTrace();
        }
        return ResponseUtils.error(1, "更新购物车失败");
    }

    /**
     * 删除购物车商品
     * @param cartIds
     * @param userId
     * @return
     */
    @Override
    public Response<Boolean> deleteCart(List<String> cartIds, Long userId,Long shopId) {
        try {
            // 用户已登录,查询登录状态的购物车
            String key = CacheConstant.RL_CART + userId + ":" + shopId;
            BoundHashOperations<String, Object, Object> hashOperations = this.redisTemplate.boundHashOps(key);
            cartIds.forEach(hashOperations::delete);
            return ResponseUtils.success(Boolean.TRUE);
        } catch (Exception e){
            e.printStackTrace();
        }
        return ResponseUtils.error(1, "删除购物车商品失败");
    }


    /**
     * 删除购物车所有商品
     * @param userId
     * @return
     */
    @Override
    public Response<Boolean> deleteAllCart(Long userId,Long shopId) {
        try {
            // 用户已登录,查询登录状态的购物车
            String key = CacheConstant.RL_CART + userId + ":" + shopId;
            // 获取所有ids
            BoundHashOperations<String, Object, Object> hashOperations = this.redisTemplate.boundHashOps(key);
            List<String> ids = hashOperations.values().stream().map(userCartJson-> {
                Cart cart = JSON.parseObject(userCartJson.toString(), Cart.class);
                return cart.getCartItemId();
            }).collect(Collectors.toList());
            // 删除
            hashOperations.delete(ids.toArray());
            return ResponseUtils.success(Boolean.TRUE);
        } catch (Exception e){
            e.printStackTrace();
        }
        return ResponseUtils.error(1, "删除购物车商品失败");
    }
}

ProductSkuServiceImpl.class:SKUService

@Service
@AllArgsConstructor
public class ProductSkuServiceImpl extends CurdServiceImpl<ProductSku, ProductSkuDao> implements ProductSkuService {

    private final StringRedisTemplate redisTemplate;

    @Override
    @Transactional
    public Boolean batchUpdate(Long productId, List<ProductSku> skuList) {
        Assert.notNull(productId, "更新的商品id不能为空");

        this.batchLogicDelete(productId);

        skuList.forEach(productSku -> {
            productSku.setStatus(DataStatus.NORMAL.getStatus());
            this.update(productSku);

            // 判断是否存在这个Key
            if(redisTemplate.hasKey(CacheConstant.RL_SKU + productSku.getId().toString())){
                // 更新redis 中 sku 的价格(折扣价)
                redisTemplate.opsForValue().set(CacheConstant.RL_SKU + productSku.getId().toString(), productSku.getDiscountPrice().toString());
            }
        });
        return true;
    }
}

ProductPropertyServiceImpl.class:属性Service

@Service
@AllArgsConstructor
public class ProductPropertyServiceImpl extends CurdServiceImpl<ProductProperty, ProductPropertyDao> implements ProductPropertyService {

    private final StringRedisTemplate redisTemplate;

    @Override
    @Transactional
    public Boolean batchUpdate(Long productId, List<ProductProperty> properties) {
        Assert.notNull(productId, "更新的商品id不能为空");

        this.batchLogicDelete(productId);

        properties.forEach(productProperty -> {
            productProperty.setStatus(DataStatus.NORMAL.getStatus());
            this.update(productProperty);
            // 判断是否存在这个Key
            if(redisTemplate.hasKey(CacheConstant.RL_PROP + productProperty.getId().toString())){
                // 更新redis 中 属性的价格(折扣价)
                redisTemplate.opsForValue().set(CacheConstant.RL_PROP + productProperty.getId().toString(), productProperty.getPrice().toString());
            }
        });
        return true;
    }
}

前端报文:

{
    "discountPrice":"0.10",
    "images":"https://sh-cdn.xiaoyisz.com/prod/b66562d5-5903-4c-8-.jpg",
    "name":"拉尔夫滴滤咖啡",
    "price":"0.10",
    "productId":"1377566813235318784",
    "propValues":"杯型:标准杯;糖:标准;奶油:标准;特殊要求:标准",
    "propertys":[
        {
            "id":"1377566813252096000",
            "status":1,
            "createTime":"2021-04-01T18:21:37",
            "updateTime":"2021-04-12T19:56:09",
            "productId":"1377566813235318784",
            "propId":"1377469870433767424",
            "propName":"杯型",
            "rule":1,
            "propValue":"标准杯",
            "price":0,
            "sequence":1,
            "groupSequence":1,
            "visible":1
        },
        {
            "id":"1377566813264678912",
            "status":1,
            "createTime":"2021-04-01T18:21:37",
            "updateTime":"2021-04-12T19:56:09",
            "productId":"1377566813235318784",
            "propId":"1377471375027081216",
            "propName":"糖",
            "rule":2,
            "propValue":"标准",
            "price":0,
            "sequence":1,
            "groupSequence":1,
            "visible":1
        },
        {
            "id":"1377566813285650432",
            "status":1,
            "createTime":"2021-04-01T18:21:37",
            "updateTime":"2021-04-12T19:56:09",
            "productId":"1377566813235318784",
            "propId":"1377550487712305152",
            "propName":"奶油",
            "rule":3,
            "propValue":"标准",
            "price":0,
            "sequence":1,
            "groupSequence":1,
            "visible":1
        },
        {
            "id":"1377566813294039040",
            "status":1,
            "createTime":"2021-04-01T18:21:37",
            "updateTime":"2021-04-12T19:56:09",
            "productId":"1377566813235318784",
            "propId":"1357232629233094656",
            "propName":"特殊要求",
            "rule":4,
            "propValue":"标准",
            "price":0,
            "sequence":1,
            "groupSequence":1,
            "visible":1
        }
    ],
    "quantity":1,
    "subtitle":"Ralph’s Coffee",
    "skuId":"1377566813243707392",
    "canTakeout":1,
    "packingFee":0,
    "check":true
}

四、Redis持久化配置

这里采用的AOF持久化(即Append Only File持久化),AOF工作机制很简单,redis会将每一个收到的写命令都通过write函数追加到文件中。通俗的理解就是日志记录。

# 1. 编辑Redis配置文件
vim redis.conf 

# 2. 修改配置文件内容

appendonly yes                   #开启AOF持久化

appendfilename "appendonly.aof"  #配置AOF持久化文件名

appendfsync everysec             #配置AOF持久化策略

#always    表示只要缓冲区中数据发生更改,则就将该数据写入到aof文件中
#everysec  每秒写入把缓冲区中数据写入aof文件中(redis默认)
#no        不做任何策略配置,将策略的配置交给操作系统,一般操作系统是等待缓冲区被占完之后,将数据写入aof文件中

五、总结

到这里我们就实现了使用Redis实现购物车,大家可以根据自身业务结合使用,代码中基本都添加了注释。其实Redis实现购物车的难点就在于价格计算和价格变更,当商品的价格做了变更时需要根据业务赋予的Key找到对应Redis的数据进行修改,以便在查看购物车时在返回数据做价格计算时是一个正确的价格。

Tags:hashoperations

控制面板
您好,欢迎到访网站!
  查看权限
网站分类
最新留言