当前位置: 首页 > news >正文

商城笔记-----

sale_attr_value_id不为null的话is_check就是1

查出所有销售属性名和值并且用ischeck标记出当前sku

select ssa.*, ssav.id vid, ssav.sale_attr_value_name, IF(skuv.sale_attr_value_id IS NULL, "0", "1") is_checked from spu_sale_attr ssa left join spu_sale_attr_value ssav on ssa.spu_id = ssav.spu_id and ssa.base_sale_attr_id = ssav.base_sale_attr_id left join sku_sale_attr_value skuv on skuv.sku_id = #{skuId} and skuv.sale_attr_value_id = ssav.id where ssa.spu_id = #{spuId} order by ssa.base_sale_attr_id, ssav.id

这块两个查询:查询所有销售属性并且用ischeck表示当前sku是哪种销售属性(ischeck表示)。查询所有销售属性的组合,并且表示是哪种sku。

(sale_attr_value_id|sale_attr_value_id:skuid)

把这两个数据给前端,前端就能确定当前sku的销售属性是哪个组合,并且切换销售属性,前端就能知道往后端发送请求时候携带的skuid了。

用户切换一次销售属性,就往后端发送一次请求,并且携带相应的skuid

<select resultType="com.atguigu.gmall.product.dto.ValueSkuJsonDTO"> select a.sku_id, GROUP_CONCAT(DISTINCT a.sale_attr_value_id ORDER BY a.sale_attr_value_id ASC SEPARATOR '|') attr_value_concat from (select skuv.sku_id, skuv.sale_attr_value_id from sku_sale_attr_value skuv left join spu_sale_attr_value ssav on skuv.sale_attr_value_id = ssav.id where skuv.spu_id = #{spuId} ORDER BY skuv.sku_id, ssav.base_sale_attr_id, ssav.id) a GROUP BY a.sku_id </select>

嵌套三级分类

@Data public class CategoryVo { private Long categoryId; //当前分类id private String categoryName; //当前分类名 private List<CategoryVo> categoryChild; //子分类 } <resultMap type="com.atguigu.gmall.web.CategoryVo"> <id property="categoryId" column="c1id"></id> <result property="categoryName" column="c1name"></result> <!-- 一级分类 --> <collection property="categoryChild" ofType="com.atguigu.gmall.web.CategoryVo"> <id property="categoryId" column="c2id"></id> <result property="categoryName" column="c2name"></result> <!-- 二级分类 --> <collection property="categoryChild" ofType="com.atguigu.gmall.web.CategoryVo"> <id property="categoryId" column="c3id"></id> <result property="categoryName" column="c3name"></result> <!-- 三级分类 --> </collection> </collection> </resultMap> <select resultMap="CategoryTreeRM"> select bc1.id c1id, bc1.name c1name, bc2.id c2id, bc2.name c2name, bc3.id c3id, bc3.name c3name from base_category1 bc1 left join base_category2 bc2 on bc2.category1_id = bc1.id left join base_category3 bc3 on bc3.category2_id = bc2.id </select>

1、查询三级分类加了map缓存,吞吐量由300/s到8500/s。

2、缓存没有查询数据库==回源

一系列解决方案

1缓存数据,有bug

try{ //1、查询redis String json = redisTemplate.opsForValue().get(key); if(StringUtils.isEmpty(json)){ return null; }else { //解决穿透,设置null值,不过我们设置的是x字符串。或者不用设置x,直接用布隆过滤器,把这个判断删除就行 if("x".equals(jsonStr)){ return null; } //3、缓存中有。直接返回 return json ; } //解决穿透 //布隆 RBloomFilter<Object> filter = redissonClient.getBloomFilter(bloomKey); //判断布隆有没有 if (!filter.contains("xxx")) { return null; } //解决击穿 //锁名一定不要为固定值,一旦为固定值查49,50商品为同一把锁。 RLock lock = redissonClient.getLock("lock-" + skuId); //阻塞式加锁(无限等待,设置释放时间就不会无限等待了), // 一定要等到锁。会进行续期,默认30秒,每隔10秒续到30秒。 // 参数:释放时间,单位。 // lock.lock(10, TimeUnit.SECONDS); //开启锁功能.尝试加锁。返回值是布尔类型。三个参数:等待时间(最多等多久),释放时间,单位 boolean b = lock.tryLock(); if (b) { //得到锁的逻辑 //8、加锁成功。回源。双检查机制:回源之前再查询一次缓存。(此代码没查缓存)原因: //两个线程同时发起抢锁命令,一个卡住了,别人释放后,另一个拿到锁 //10、目标方法执行。如果自己抓异常一定要往出抛,否则多切面情况下有可能引起切面逻辑失效 result = pjp.proceed(args);//回源代码 //11、放入缓存,缓存中的每个数据都应该有过期时间;临时数据缓存短一点时间 String jsonData = data==null? "x":Jsons.toStr(data); //缓存中的每个数据都应该有过期时间;临时数据缓存短一点时间 if(data == null){ redisTemplate.opsForValue().set(key,jsonData,30,TimeUnit.MINUTES);//存x,时间短一点 }else { redisTemplate.opsForValue().set(key,jsonData,ttl,timeUnit);//存商品详情,时间长一点 } //12、解锁放到finally return result; }else { //没得到锁的逻辑 //9、加锁失败。睡500毫秒再次查询缓存· Thread.sleep(500); return cacheOpsService.getCacheData(cacheKey, new TypeReference<Object>() { @Override public Type getType() { return methodReturnType; } }); } }finally { //redisson自动判断是不是自己的锁 //解锁一定要放到finally,不然会出现幽灵续期 lock.unlock(); } ----------------------------- 延迟双删 //这个池子的队列是Integer.MAX;容易OOM ScheduledExecutorService pool = Executors.newScheduledThreadPool(4); @Autowired StringRedisTemplate redisTemplate; @Override public void updateSkuInfo(SkuInfoUpdateVo vo) { //1、去数据库修改 //修改数据库数据的代码没写 //2、延迟双删 //2.1)、立即删 redisTemplate.delete(RedisConst.SKU_DETAIL_CACHE_PREFIX + vo.getId()); //提交延迟任务。有OOM风险 pool.schedule(()->{ redisTemplate.delete(RedisConst.SKU_DETAIL_CACHE_PREFIX+vo.getId()); },10, TimeUnit.SECONDS); } ------------------------------- 布隆过滤器 --初始化代码就是下面的代码。service-product进行初始化,因为查skuid方便 @PostConstruct public void initSkuIdBloom(){ //1、初始化布隆 RBloomFilter<Object> filter = redisson.getBloomFilter(RedisConst.BLOOM_SKUID); if(!filter.isExists()){ //初始化布隆 //期望插入多少数据,误判率 log.info("布隆过滤器尚未初始化,正在初始化...."); filter.tryInit(1000000,0.000001); List<Long> allSkuId = getAllSkuId(); allSkuId.stream().forEach(item->{ //查询skuid,添加skuid数据到布隆.(遍历放入) filter.add(item); }); log.info("布隆过滤器初始化完成...."); } } --查询sku详情的时候的代码 RBloomFilter<Object> filter = redissonClient.getBloomFilter(bloomKey); //判断布隆有没有 filter.contains("xxx"); --保存sku时候的布隆代码 //把商品信息添加到布隆过滤器 RBloomFilter<Object> filter = redisson.getBloomFilter(RedisConst.BLOOM_SKUID); filter.add(skuId); --重置布隆过滤器。逻辑:创建新布隆,删除老布隆和老布隆的配置,修改新布隆的名字和配置为老布隆的名字和配置 @Override public void resetBloom(String bloomSkuid) { //TODO 如何重建布隆? //删了重做? // 高速换胎 //如何尽量缩短布隆不可用时间。 布隆重置期间不可用 //1、创建一个新的布隆。保存所有数据 RBloomFilter<Object> filter = redisson.getBloomFilter(bloomSkuid + "-new"); if (!filter.isExists()) { log.info("正在重置布隆....新布隆创建中...."); filter.tryInit(1000000, 0.000001); skuInfoService.getAllSkuId().stream().forEach(item -> { filter.add(item); }); } //这步原子操作是把删除布隆和给布隆改名两步操作写成lua脚本了, //4、原子操作 (要删除的key(skuid-bloom),把更名的key(skuid-bloom-new),改为要删除的key) //KEYS[1]老布隆。KEYS[2]新布隆。 String script = "redis.call(\"del\",KEYS[1]);" + "redis.call(\"del\",\"{\"..KEYS[1]..\"}:config\");" + "redis.call(\"rename\",KEYS[2],KEYS[1]);" + "redis.call(\"rename\",\"{\"..KEYS[2]..\"
http://www.jsqmd.com/news/603268/

相关文章:

  • 贾子科学定理(Kucius Science Theorem,KST-C):重新定义“科学”为绝对真理,终结证伪主义霸权
  • 2026年SAT短期备考想高效出分?优质冲刺提分培训机构与补习机构推荐 - 品牌2026
  • 2026北京实验室认可咨询机构梯队名录 含核心服务能力对比 - 资讯焦点
  • 从零到一:基于Grafana与TDEngine构建实时业务监控看板
  • PDF表格智能提取:从数据困境到高效处理的转型指南
  • MVP.css在企业级应用中的10个终极应用场景分析:如何用最小CSS框架打造专业产品
  • 2024信息获取工具评测:Bypass Paywalls Clean内容访问助手完整使用指南
  • 如何高效使用XUnity.AutoTranslator:Unity游戏实时翻译的完整实战指南
  • 口服抗衰产品推荐,顶级期刊解读NMN抗衰临床效果:根据国际抗衰有效标准,匹配最适合国人品牌 - 资讯焦点
  • Cursor3-智能体编程时代
  • 深圳眼部修复哪家好?双眼皮失败、去眼袋失败后怎么选医生 - 讯息观点
  • 从新手到专家:Simplenote Electron的终极用户体验设计指南
  • 书匠策AI:毕业论文写作的“未来科技伙伴”,开启智能创作新纪元!
  • Open UI5 源代码解析之883:OverflowToolbar.js
  • 2026届必备的六大AI科研神器解析与推荐
  • MVP.css暗黑模式终极指南:如何完美适配用户偏好与系统设置
  • 01-16-16 命令模式 - Handler消息机制的命令封装
  • 2026华东口碑不错的高强度、耐高温复材粘接剂公司一览,四甲基二乙烯基硅氮烷,高强度、耐高温复材粘接剂企业有哪些 - 品牌推荐师
  • 收录排名查询 SEO 软件哪个好用
  • 【MLLM】Qwen-Omni系列全模态模型架构和训练
  • 告别MSE!用能量模型(EBM)做行为克隆,让机器人模仿学习更精准(附PyTorch代码)
  • 2025最权威的五大AI论文方案推荐
  • 终极图像分类指南:从海豚到多类别的机器学习实战
  • odiff在大型项目中的应用:处理25000+图像快照的最佳实践
  • vokoscreenNG:专业级开源屏幕录制解决方案的5大核心优势
  • 2026年GitHub中比较热门的skills技能
  • 告别环境配置噩梦:用Docker Desktop + WSL2在Windows上5分钟搞定vLLM运行环境
  • 2026室内灯具品牌发展趋势及品质之选 - 品牌排行榜
  • PETRV2-BEV训练效果对比展示:nuscenes高精度vs xtreme1泛化挑战
  • Win11Debloat深度解析:让Windows重获新生的系统优化神器