高并发环境下查看产品详情功能的需求分析及部分代码演示(redis缓存+mq异步实现数据同步)

Java 秒杀系统性能优化( Redis缓存 + JVM缓存 + MQ异步 ) 一、优化概述 对于秒杀系统的优化方式有很多很多,从这篇博文开始我们一步一步的对系统进行性能的优化,同时记录每一步优化的主要思路和相关的代码实现原理,并在每次优化后使用 jmeter 对系统进行压测。这篇博文主要使用 Redis 缓存、JVM 缓存和 MQ 异步执行任务来对系统进行优化。 项目源码 GitHub:https://github.com/TIYangFan/SpikeSystem(... 阅读详情

商品详情:1.重复访问过高 2.页面内容多 考虑使用缓存

缓存:可以为高频操作的数据,进行缓存处理

推荐的技术:Redis
 

缓存数据的要求:
1.高频访问
2.数据不频繁改变
3.数据不敏感 对安全要求不高


商品详情缓存策略:
1.查询商品详情-先检索Redis
2.Redis存在 直接返回
3.Redis不存在--查询数据库----存入Redis一份(缓存)---结果返回
4.再有请求--->Redis--->返回
Redis如何存储
1.抉择数据类型 5种
不需要有效期 永久有效 下架的时候,记得删除缓存
Hash:类型 Key: micro:product:detail
键值对:键:商品的id 值:对应商品详情信息:商品信息、图册信息、详情信息、属性信息等(字符串
(json)、序列化(类的结构不要改变))
ps:如果数据量过大,可以考虑用多个Hash来存储,数据分片:
比如可以设置一个Hash的存储上限(比如1000)。现在有88000条商品,可以对商品id进行取余对1000,根据余
数选择对应的Hash,Hash的Key的格式:micro:product:detail:余数
如果id不连续,可以考虑在Redis新增一个String类型:key:product:detail:count 值:缓存的商品详情的数量
incr
分片存储的逻辑:
1.缓存数据-先获取product:detail:count 存在:自增,不存在:新增 1
2.获取product:detail:count 的值
3.根据上面的值对1000取余
4.根据余数选择对应的Hash,Hash的Key的格式:micro:product:detail:余数
如果Mysql发送数据变化,那么就会带来Redis和Mysql的数据不一致
1.简单 通用
后台系统更改商品信息的时候,修改成功之后,校验该商品是否有缓存,有的话直接修改
2.定时任务
指定间隔时间,cron表达式 间隔一定的时间,重复执行
定时任务触发的时候,查询商品修改流水表 根据时间进行查询:betweeb 当前时间-间隔时间 and 当前时间
查询间隔时间内修改的商品id(注意去重)
查询修改商品的详情信息,去Redis校验该商品是否做缓存,如果缓存,就需要更新缓存数据
缺点:
1.间隔时间 数据可能不一致
2.临界时间点
3.定时任务挂掉
MQ异步实现数据的同步
后台系统更改商品信息的时候,修改成功之后,发送MQ消息(商品信息)
发送指定的队列,消息监听器-监听消息变化,验证Redis中商品是否做缓存,有缓存更新
 

代码演示:
商品服务:

package com.lxm.productservice.service.impl;

import com.lxm.common.config.RedisKeyConfig;
import com.lxm.common.dto.PmsProductDetailDto;
import com.lxm.common.dto.PmsProductDto;
import com.lxm.common.utils.RUtil;
import com.lxm.common.utils.RedissionCore;
import com.lxm.common.vo.R;
import com.lxm.productservice.dao.PmsProductDao;
import com.lxm.productservice.service.PmsProductService;
import org.springframework.stereotype.Service;

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

/**
 * @Author LXM
 * @Date 2020/7/15 0015
 */
@Service
public class PmsProductServiceImpl implements PmsProductService {
    @Resource
    private RedissionCore redissionCore;
    @Resource
    private PmsProductDao dao;

    /**
     * 按条件查询商品列表
     * @param parms
     * @return
     */
    @Override
    public R searchList(Map<String, Object> parms) {
        List<PmsProductDto> pmslist=dao.querylist(parms);
        return RUtil.ok(pmslist);
    }

    /**
     * 查询商品详情
     * @param id
     * @return
     */
    @Override
    public R searchDetail(int id) {
        //先检查redis中是否有商品详情的缓存
        if(redissionCore.checkMap(RedisKeyConfig.PRODUCT_DETAIL,id+"")){
            //redis中有缓存,取出缓存,返回结果
            return RUtil.ok(redissionCore.getMap(RedisKeyConfig.PRODUCT_DETAIL,id+""));

        }else {
            //redis中没有缓存,向数据库中查询
            PmsProductDetailDto detailDto=dao.querydetail(id);
            //判断返回结果是否为空
            if(detailDto!=null){
                //如果商品数据量过大,可以考虑对商品进行分片存储
                //将查询的结果存入redis缓存中
                redissionCore.addMap(RedisKeyConfig.PRODUCT_DETAIL,id+"",detailDto);
                //返回查询结果
                return RUtil.ok(detailDto);
            }else{
                //在数据库没有查询到商品,可能商品下架或者其他情况
                return RUtil.error("商品走丢了");
            }

        }
    }
}
package com.lxm.productservice.dao;

import com.lxm.common.dto.PmsProductDetailDto;
import com.lxm.common.dto.PmsProductDto;

import java.util.List;
import java.util.Map;

public interface PmsProductDao {
    /**
     * 查询商品详情
     * @param id
     * @return
     */
    PmsProductDetailDto querydetail(int id);

    /**
     * 按条件查询商品
     * @param parms
     * @return
     */
    List<PmsProductDto> querylist(Map<String, Object> parms);
}


同步代码:



/**
 * @Author LXM
 * @Date 2020/7/16 0016
 */
@Configuration
public class RabbitMqConfig {
    @Bean
    public Queue createProductDetail(){
        return new Queue("micro:product:detail");
    }
   
}
package com.lxm.productservice.listener;

import com.lxm.common.config.RedisKeyConfig;
import com.lxm.common.dto.MqMessageDto;
import com.lxm.common.dto.PmsProductDetailDto;
import com.lxm.common.utils.RedissionCore;
import com.lxm.productservice.dao.PmsProductDao;
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
 * 当后台修改商品信息的时候,修改成功之后,发送mq消息
 * 消息监听器监听队列,判断redis中是否有缓存,如果有缓存,更新数据
 * @Date 2020/7/16 0016
 */
@Component
@RabbitListener(queues = "micro:product:detail")
public class ProductDetailListener {
    @Resource
    private RedissionCore redissionCore;
    @Resource
    private PmsProductDao dao;

    /**
     * 当后台修改商品信息的时候,修改成功之后,发送mq消息
     * 消息监听器监听队列,判断redis中是否有缓存,如果有缓存,更新数据
     * @param obj
     */
    @RabbitHandler
    public void handler(Object obj){
        //校验消息
        if(obj instanceof MqMessageDto){
            MqMessageDto dto=(MqMessageDto) obj;
            //获取队列中的信息--商品id
            int id=(Integer) dto.getMsg();
            //校验redis中是否有缓存
            if (redissionCore.checkKey(RedisKeyConfig.PRODUCT_DETAIL)){
                if (redissionCore.checkMap(RedisKeyConfig.PRODUCT_DETAIL,id+"")){
                    //redis中有缓存,对redis中的缓存进行更新
                    //查询数据库中的数据,将数据添加到redis缓存中
                    PmsProductDetailDto detailDto=dao.querydetail(id);
                    redissionCore.addMap(RedisKeyConfig.PRODUCT_DETAIL,id+"",detailDto);
                }
            }
        }
    }

}

封装的工具类

package com.lxm.common.utils;

import com.lxm.common.config.RedisKeyConfig;
import org.redisson.Redisson;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;

import javax.annotation.Resource;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * @Author LXM
 * @Date 2020/7/11 0011
 */
public class RedissionCore {
    private RedissonClient client;
    public RedissionCore(String host,int port,String pwd){
        Config config=new Config();
        config.useSingleServer().setAddress("redis://"+host+":"+port).setPassword(pwd);
        client= Redisson.create(config);
    }

    /**
     * 添加字符串
     * @param key
     * @param val
     */
    public void addStr(String key,String val){
        client.getBucket(key).set(val);
    }

    /**
     * 添加字符串并设置过期时间
     * @param key
     * @param val
     * @param seconds
     */
    public void addStr(String key,String val,long seconds){
        client.getBucket(key).set(val,seconds, TimeUnit.SECONDS);
    }

    /**
     * 向map集合中添加数据
     * @param key
     * @param f
     * @param v
     */
    public void addMap(String key,String f,String v){
        client.getMap(key).put(f,v);
    }
    public void addMap(String key,String f,Object v){
        client.getMap(key).put(f,v);
    }
    /**
     * 向map集合中一次添加整个集合
     * @param key
     * @param map
     */
    public void addMap(String key, Map<String,String> map){
        client.getMap(key).putAll(map);
    }

    /**
     * 删除map集合中的某个键值对
     * @param key
     * @param f
     */
    public void delMap(String key,String f){
        client.getMap(key).remove(f);
    }

    /**
     * 删除某个key
     * @param key
     */
    public void delKey(String key){
        client.getKeys().delete(key);
    }

    /**
     * 删除多个key
     * @param keys
     */
    public void delKeys(String... keys){
        client.getKeys().delete(keys);
    }

    /**
     * 从字符串中获取值
     * @param key
     * @return
     */
    public String getStr(String key){
        return client.getBucket(key).get().toString();
    }

    /**
     * 从map中获取值
     * @param key
     * @param f
     * @return
     */
    public String getMap(String key,String f){
        return client.getMap(key).get(f).toString();
    }
    public Map<Object, Object> getMap(String key){
        return client.getMap(key);
    }

    /**
     * 检查map集合中是否存在key
     * @param key
     * @param f
     * @return
     */
    public boolean checkMap(String key,String f){
        return client.getMap(key).containsKey(f);
    }

    /**
     * 检查该key是否存在
     * @param key
     * @return
     */
    public boolean checkKey(String key){
        return client.getKeys().countExists(key)>0;
    }

    /**
     * 检查set集合中该key是否存在
     * @param key
     * @param val
     * @return
     */
    public boolean checkSet(String key,String val){
        return client.getSet(key).contains(val);
    }

    /**
     * 给某个key设置有效期
     * @param key
     * @param seconds
     */
    public void setTime(String key,long seconds){
        client.getKeys().expire(key,seconds,TimeUnit.SECONDS);
    }

    /**
     * 给某个key上锁
     * @param key
     * @return
     */
    public RLock lock(String key){
        RLock rl=client.getLock(key);
        rl.lock(RedisKeyConfig.LOCK_Time,TimeUnit.SECONDS);
        return rl;
    }

    /**
     * 给某个key手动解锁
     * @param key
     */
    public void unlock(String key){
        client.getLock(key).unlock();
    }
}
package com.lxm.common.vo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

/**
 * @Author LXM
 * @Date 2020/7/9 0009
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
public class R {
    private Integer code;
    private String msg;
    private Object data;
}
package com.lxm.common.utils;


import com.lxm.common.config.ResultCodeConfig;
import com.lxm.common.vo.R;

/**
 * @program: HungryApi
 * @description: 封装对统一结果的操作
 * @author: Feri(邢朋辉)
 * @create: 2020-06-18 10:28
 */
public class RUtil {
    public static R ok(String msg, Object data){
        return new R(ResultCodeConfig.R_SUCCESS,msg,data);
    }

    public static R ok(Object data){
        return new R(ResultCodeConfig.R_SUCCESS,"OK",data);
    }

    public static R ok(){
        return new R(ResultCodeConfig.R_SUCCESS,"OK",null);
    }

    public static R error(String msg){
        return new R(ResultCodeConfig.R_ERROR,msg,null);
    }
    public static R error(){
        return new R(ResultCodeConfig.R_ERROR,"失败",null);
    }
}


 

多级缓存架构一致性终极指南 — — 从本地缓存到 MQ / Redis / CDC 的完整工程设计 多级缓存一致性没有银弹。真正的答案不是“选哪种方案”,而是构建一套具备:分类治理 + 多重校验 + 自愈能力 + 监控告警的完整体系。 阅读详情

相关推荐

【架构进阶】高并发场景下库存扣减的终极方案:Redis Lua + MQ 异步落库实战

本文针对电商秒杀等高并发场景下的库存扣减问题,提出了一套从数据库锁到Redis原子脚本再到MQ异步削峰的架构演进方案。传统数据库方案在高并发下存在连接池耗尽、行锁竞争和超卖风险。通过Redis Lua脚本实现原子性扣减和业务校验,QPS可达数万。进一步引入MQ异步解耦,将订单信息异步落库,缓解数据库压力。文章还总结了生产环境中的典型问题及解决方案,如Redis主从切换、MQ消息积压等,并通过性能测试对比验证了方案的优越性。最终指出架构设计需权衡性能、一致性和复杂度,针对不同业务场景选择合适方案。

运维人生 959

基于SpringBoot+RabbitMQ+Redis开发的秒杀系统,实现异步下单、热点数据缓存、解决超卖等问题

秒杀项目:SeckillProject 一、项目简介:  ​ ​ ​ ​SeckillProject基于Springboot开发的秒杀系统,实现的功能主要是登录、商品列表、商品详情、秒杀商品,订单详情等功能。在系统业务处理中,使用到分布式session维持会话、Redis预减库存降低数据库访问压力,消息队列异步下单(削峰)、客户端轮询结果、接口限流防刷等。 项目地址: https://github.com/pure-xiaojie/SeckillProject(希望

笃行 4267

LMS Virtual.Lab二次开发:声学仿真结果导出方法(VBScript、Python)

Siemens LMS Virtual.Lab 提供一套集成软件平台用以模拟机械系统的品质属性,如结构完整性、振动噪声、耐久性、系统动力学特性、驾驶的平顺性及操纵的稳定性等。

爱看书的小沐 6021

Java高并发秒杀平台(Redis + RabbitMQ)

Seconds-Kill 本项目是一个模拟高并发环境下基于 SpringBoot 的秒杀购物平台。为了减少对数据库的直接访问,通过 Redis 实现了缓存优化;并通过 RabbitMQ 消息中间件来接收大量的并发请求,实现异步和削峰,然后再慢慢地更新数据库。最后通过 Jmeter 压测工具,可以很好地对比优化前后的 QPS… 项目的源代码:基于 SpringBoot 的高并发秒杀平台 quick-...

Apple_hzc的博客 9696

Nornir自动化简单介绍-网络设备信息收集

作为网工,学会通过执行脚本,可以自动化的完成日常一些设备相关配置或信息收集等工作,可以说是事半功倍。 Nornir就是这样一个自动化网络运维工具。按照官网上的说明: Nornir是用python编写的自动化框架,可与python一起使用。Nornir旨在通过提供一个纯Python框架来解决这些问题。 详细参考: Github GitHub - nornir-automation/nornir: Pluggable multi-threaded framework with inventory .

Gun&rose 7806

三甲医院网络架构与安全建设实战

华为OceanStor] [华为OceanStor][PACS存储双活] [HIS数据库同步]患者隐私 数据脱敏 天清Web防火墙动态脱敏策略。主数据中心 --[OTV专线]-- 备数据中心。实现医疗业务网/卫生专网/互联网三网隔离。核心业务配置(华为CE6865)自动备份配置(每天02:00)安全事件响应(30分钟SLA)漏洞扫描(每周日00:00)实现医疗物联网统一接入管控。五、等保2.0合规关键配置。堡垒机登录(双因素认证)四、医疗物联网安全方案。

有小小的远大抱负 1911

使用RabbitMQ+Redis实现秒杀系统

秒杀系统就是电商系统的一种形式,通过设计秒杀模块来应对实际电商平台中最考验系统架构的部分。秒杀系统特点:业务简单(卖家查询,买家下订单减库存),瞬时并发量高。

shisi_ixz的博客 2150

MATLAB2021b详细安装教程

1.下载 2.安装 下载安装包后打开iso文件,若是无法打开请用解压软件打开。 ①打开MATLAB_R2021b_win64,双击软件开始安装 ② 一直点击下一步,直到步骤③ ③选择我已有我的许可证的文件密钥,并输入62551-02011-26857-57509-64399-54230-13279-37181-62117-65158-40352-64197-45508-24369-45954-39446-39538-16936-10698-58393-44718-32560-10501-40

惜洛-Jankin的博客 9万+

高并发处理之商品详情页

卜大伟2019-01-18 11:13:472487收藏4 分类专栏:高并发 该文章是根据velocity 2015技术大会的演讲《京东网站单品页618实战》细化而来,希望对大家有用。 商品详情页是什么 商品详情页是展示商品详细信息的一个页面,承载在网站的大部分流量和订单的入口。京东商城目前有通用版、全球购、闪购、易车、惠买车、服装、拼购、今日抄底等许多套模板。各套模板的元数据是一样的,只是展示方式不一样。目前商品详情页个性化需求非常多,数据来源也是非常多的,而且许多基...

wangzhipeng47的博客 1826

1. 在 SAP ABAP 事物码 SEGW 里创建 SAP OData 项目

本文介绍如何在 SAP ABAP 事物码 SEGW 里创建 SEGW 项目,使用工具生成 Runtime 运行时需要的资源。

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 5446

解读 2025《高质量数据集 质量评测规范》

《高质量数据集质量评测规范》为2025年数据质量评估提供标准化框架,适用于政府部门、AI企业、数据服务商等行业主体。规范以"说明文档-数据质量-模型应用"三维体系为核心:明确定义高质量数据集分类,细化各项指标要求(包括文档完整性、数据规范性、应用多样性等),并提供具体评分细则(百分制,90分达标)和计算方法。附录补充多模态数据处理细则,旨在建立可操作的质量评估标准,保障优质数据供给流通。

cdfunlove的博客 1890

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

电商、外卖、直播等平台基本上都有购物车的功能。 购物车的作用: 1.需要购物的商品的保存 2.购物车可以充当收藏 购物车都需要设置商品的上限 购物车需要接口 1.查询登录用户的购物车列表数据 2.商品详情页、商品列表页 可以加入购物车 3.购物车列表页 可以实现商品数量的变化:增加、减少 实现思路 1.直接操作数据库 用的比较多 如果数据量大或者并发量大的 就会对系统很大压力 加减直接操作数据库 2.使用Redis+Mysql 1.直接对购物车表做缓存 Redis 做购物车的缓存,后面的操作都操作Red

Java_LXM的博客 3627

MDIO接口协议与其详解——单片机

在单片机领域,通过MDIO接口可以与外部设备进行通信,实现对设备的控制和数据的读写。通过本文的介绍,你可以了解到MDIO接口协议的原理和使用方法,并参考源代码示例进行实际的开发和应用。具体的初始化方法与单片机的型号和开发环境有关,可以参考相应的单片机手册和开发工具的文档。(1)发送读取命令:向MDIO线发送读取命令,通常是发送一个特定的控制字节,用于指示要读取的寄存器地址。(1)发送写入命令:向MDIO线发送写入命令,通常是发送一个特定的控制字节,用于指示要写入的寄存器地址。二、MDIO接口协议使用方法。

web_class282的博客 2627

MySQL数据同步到 Redis 缓存的几种方法

MySQL数据同步到 Redis 缓存的几种方法

吴名氏的博客 13万+

汉书HE8,好用的汇编代码编写工具

汉书HE8,好用的汇编代码编写工具早期编写汇编代码所用功能强大

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

Spring Boot + Redis + MQ实现高并发点赞功能:项目实战

开心一笑 【最后一次警告看我优快云博客的人,你们都他妈给老子小心点,首先我不管你是什么身份,什么背景,混的有多牛逼,是不是老板,是不是社会人,这些我都不知道,我也都不在意,你们给我记住,都给我认真点看清楚:最近天气实在很凉,大家多穿衣服,别着凉了,知道不!】 课程介绍 《SpringBoot + Redis + MQ 高并发点赞项目实战》是一套项目实战的项目,通过该项目的学

IT技术分享 2万+

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

多级缓存同步更新操作的优化策略——MQ

采用异步处理多级存储结构的更新操作,以提高响应效率,同时也考虑数据一致性问题

m0_73500407的博客 2169

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

【HBZ分享】Redis如何与Mysql做数据同步,有几种方法?

Redis如何与Mysql做数据同步,有几种方法?

a645293829的博客 7584

分享如何通过Mq、Redis、XxlJob实现算法任务的异步解耦调度

欢迎讨论交流~

m0_74969835的博客 1547

[超轻量级消息队列(MQ)] Redis 不只是缓存:我用 Redis Stream 实现了一个 MQ(自定义注解方式)

Redis Stream 作为轻量级消息队列的实践 本文介绍了如何利用 Redis 5.0 引入的 Stream 数据结构实现轻量级消息队列。相比传统 MQ 方案,Redis Stream 提供了消息持久化、消费者组、ACK 确认等核心功能,同时运维成本更低。 文章详细讲解了 Redis Stream 的核心概念和关键命令: XGROUP CREATE 创建消费者组 XADD 发送消息 XREADGROUP 消费消息 XACK 确认消息 通过模拟订单支付业务场景,展示了命令的实际使用流程。最后介绍了基于 S

小名同学 4万+

ElasticSearch 和 MySQL 数据同步方案,Redis 和 MySQL 数据同步方案

ElasticSearch 和 MySQL 数据同步方案,Redis 和 MySQL 数据同步方案

道友 1200

面试八股之Redis篇1.9——缓存——异步通知的两种方式MQ&Canal

🔥本篇概览:详细讲解了两种异步通知方式MQ和Canal的区别及使用。

做一个善良的人,做好自己的事,如果愿意,再发一份光。 1027

高并发点赞项目案例

高并发点赞问题 高并发请求下,服务器频繁创建线程。 高并发请求下,数据库连接池中的连接数有限。 高并发请求下,点赞功能是同步处理等。 解决办法: 第一步 我们通过引入Redis缓存避免高并发写数据库而造成数据库压力,同时引入Redis缓存提高读的性能,基本可以解决问题。 第二步 为了解决高并发请求下,点赞功能同步处理所带来的服务器压力(Redis缓存的压力或数据库压力等),我们引入MQ消息中间件进行异步处理,用户每次点赞都会推送消息到MQ服务器并及时返回,这样用户的点赞请求就及时结束,避免了点赞请求线程

Fire_Sky_Ho的博客 6563

MQ数据同步Redis与DB实时数据一致性问题研究

实时性的数据,一般业务管理数据都是基本上不发生变化的,而发生随时不停发生变化的数据我们将之称之为实时性高的数据叫实时数据。实时数据很难保证在不同数据源下的一致性,除非查看的是某一时刻的数据快照(历史快照),否则很难保持不同数据源数据之间没有差异。所以,从实践中得出的结论是:异构多数据源保证实时数据一致性是一个伪命题,缓存的使用具有不可逆的特性,大多数情况下缓存不能当作真实数据源。 预设场景 欲实现移动App人员位置管理,要求: 1、展示用户总数和在线数量,数据交互到REDIS。 2、通过用户在线情况

纸上得来终觉浅,绝知此事要躬行 2955
上一篇: springboot 中 spring Task 及 CRON 表达式的使用--会员生日提醒举例
下一篇: 高并发环境下频繁更改购物车中的商品数量的实现思路及部分代码实现(只对购物车中的商品数量做缓存)——redis做缓存mq将redis中修改的数据同步到数据库
Java_LXM
博客等级 码龄7年 39粉丝 32原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值