热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

mysql商城热销榜怎么实现_Redis实现商品热卖榜

Redis系列redis相关介绍redis是一个key-value存储系统。和Memcached类似,它支持存储的value类型相对更多,包括strin

Redis系列

redis相关介绍

redis是一个key-value存储系统。和Memcached类似,它支持存储的value类型相对更多,包括string(字符串)、list(链表)、set(集合)、zset(sorted set --有序集合)和hash(哈希类型)。这些数据类型都支持push/pop、add/remove及取交集并集和差集及更丰富的操作,而且这些操作都是原子性的。在此基础上,redis支持各种不同方式的排序。与memcached一样,为了保证效率,数据都是缓存在内存中。区别的是redis会周期性的把更新的数据写入磁盘或者把修改操作写入追加的记录文件,并且在此基础上实现了master-slave(主从)同步。

Redis 是一个高性能的key-value数据库。 redis的出现,很大程度补偿了memcached这类key/value存储的不足,在部 分场合可以对关系数据库起到很好的补充作用。它提供了Java,C/C++,C#,PHP,Javascript,Perl,Object-C,Python,Ruby,Erlang等客户端,使用很方便.

今天我们来利用Redis来实现一个大家在工作中都可能遇到的需求,热卖排行榜

话不多说开干!!!!!

需求说明

1、本次我们实现一个每日热卖商品排行榜的需求

2、简单的设计俩张表:goods(商品表)、sell(销售记录表)

3、主要是将当日热卖的商品查询出来,利用Redis的有序集合进行大到小排序显示在前端页面

技术列表

Springboot 2.1.2.RELEASE

Redis

freemarker

mybatis-plus 3.2.0

hutool-all

搭建项目基础环境

首先我们来创建一个springboot项目,并且引入需要的依赖,后续需要的依赖后面用到在引入

81ffeb8eccd84e504588a444a88469a1.png

所有的依赖如下:

org.springframework.boot

spring-boot-starter-data-redis

org.springframework.boot

spring-boot-starter-freemarker

org.springframework.boot

spring-boot-starter-web

mysql

mysql-connector-java

runtime

org.projectlombok

lombok

true

com.baomidou

mybatis-plus-boot-starter

3.2.0

com.baomidou

mybatis-plus-generator

3.2.0

p6spy

p6spy

3.8.6

org.apache.commons

commons-lang3

3.9

cn.hutool

hutool-all

4.1.17

由于我们项目用到的模本引擎是freemarker下面简单的介绍一下这个模版引擎

FreeMarker是一款模板引擎:即一种基于模板和要改变的数据, 并用来生成输出文本(HTML网页、配置文件、源代码等)的通用工具。它不是面向最终用户的,而是一个Java类库,是一款程序员可以嵌入他们所开发产品的组件.

能够很方便的对后端的数据进行渲染

敲黑板重点!!FreeMarker的宏:宏是在模板中使用macro指令定义

宏是和某个变量关联的模板片断,以便在模板中通过用户定义指令使用该变量。

大白话:就是提高前端的代码的重用

如下是本项目中用到的FreeMarker的宏

${title}

layui.cache.page = '';

layui.cache.user = {

username: '游客'

,uid: -1

,avatar: '../res/images/avatar/00.jpg'

,experience: 83

,sex: '男'

};

layui.config({

version: "3.0.0"

,base: '../res/mods/' //这里实际使用时,建议改成绝对路径

}).extend({

fly: 'index'

}).use('fly');

#macro>

由于选择的是mybatis-plus开发所以我们将代码进行生成

参考官网:mybatis-plus官网

找到代码生成器将代码拷贝到你的项目下进行必要的配置执行main方法,生成代码。如下:

c81e677404a317670bb92d80742e53f6.png

代码如下:

public class CodeGenerator {

/**

*

* 读取控制台内容

*

*/

public static String scanner(String tip) {

Scanner scanner = new Scanner(System.in);

StringBuilder help = new StringBuilder();

help.append("请输入" + tip + ":");

System.out.println(help.toString());

if (scanner.hasNext()) {

String ipt = scanner.next();

if (StringUtils.isNotEmpty(ipt)) {

return ipt;

}

}

throw new MybatisPlusException("请输入正确的" + tip + "!");

}

public static void main(String[] args) {

// 代码生成器

AutoGenerator mpg = new AutoGenerator();

// 全局配置

GlobalConfig gc = new GlobalConfig();

String projectPath = System.getProperty("user.dir");

gc.setOutputDir(projectPath + "/src/main/java");

// gc.setOutputDir("D:\\test");

gc.setAuthor("公众号:北漂码农有话说");

gc.setOpen(false);

// gc.setSwagger2(true); 实体属性 Swagger2 注解

gc.setServiceName("%sService");

mpg.setGlobalConfig(gc);

// 数据源配置

DataSourceConfig dsc = new DataSourceConfig();

dsc.setUrl("jdbc:mysql://localhost:3306/triumphxxtop?useUnicode=true&useSSL=false&characterEncoding=utf8&serverTimezone=UTC");

// dsc.setSchemaName("public");

dsc.setDriverName("com.mysql.cj.jdbc.Driver");

dsc.setUsername("root");

dsc.setPassword("root");

mpg.setDataSource(dsc);

// 包配置

PackageConfig pc = new PackageConfig();

pc.setModuleName(null);

pc.setParent("com.triumphxx");

mpg.setPackageInfo(pc);

// 自定义配置

InjectionConfig cfg = new InjectionConfig() {

@Override

public void initMap() {

// to do nothing

}

};

// 如果模板引擎是 freemarker

String templatePath = "/templates/mapper.xml.ftl";

// 如果模板引擎是 velocity

// String templatePath = "/templates/mapper.xml.vm";

// 自定义输出配置

List focList &#61; new ArrayList<>();

// 自定义配置会被优先输出

focList.add(new FileOutConfig(templatePath) {

&#64;Override

public String outputFile(TableInfo tableInfo) {

// 自定义输出文件名 &#xff0c; 如果你 Entity 设置了前后缀、此处注意 xml 的名称会跟着发生变化&#xff01;&#xff01;

return projectPath &#43; "/src/main/resources/mapper/"

&#43; "/" &#43; tableInfo.getEntityName() &#43; "Mapper" &#43; StringPool.DOT_XML;

}

});

cfg.setFileOutConfigList(focList);

mpg.setCfg(cfg);

// 配置模板

TemplateConfig templateConfig &#61; new TemplateConfig();

// 配置自定义输出模板

//指定自定义模板路径&#xff0c;注意不要带上.ftl/.vm, 会根据使用的模板引擎自动识别

// templateConfig.setEntity("templates/entity2.java");

// templateConfig.setService();

// templateConfig.setController();

templateConfig.setXml(null);

mpg.setTemplate(templateConfig);

// 策略配置

StrategyConfig strategy &#61; new StrategyConfig();

strategy.setNaming(NamingStrategy.underline_to_camel);

strategy.setColumnNaming(NamingStrategy.underline_to_camel);

strategy.setSuperEntityClass("com.triumphxx.entity.BaseEntity");

strategy.setEntityLombokModel(true);

strategy.setRestControllerStyle(true);

strategy.setSuperControllerClass("com.triumphxx.controller.BaseController");

strategy.setInclude(scanner("表名&#xff0c;多个英文逗号分割").split(","));

strategy.setSuperEntityColumns("id", "created", "modified", "status");

strategy.setControllerMappingHyphenStyle(true);

strategy.setTablePrefix(pc.getModuleName() &#43; "_");

mpg.setStrategy(strategy);

mpg.setTemplateEngine(new FreemarkerTemplateEngine());

mpg.execute();

}

}

执行main方法&#xff0c;如下&#xff0c;输入你的表名&#xff0c;生成你的代码

1479effe0d0e58a18be543f02e0b0968.png

生成代码

dce8d8593eb8becb0f854d9944f70939.png

由于我们使用的是mp所以需要配置sql分析器&#xff0c;将sql打印出来&#xff0c;便于分析&#xff0c;当然配置sql分析器是有一定的性能损耗&#xff0c;所以不建议在产线上配置&#xff0c;配置如下:

首先添加依赖

p6spy

p6spy

3.8.6

修改数据库配置信息,driver-class-name:com.p6spy.engine.spy.P6SpyDriver,jdbc后边加上p6spy

spring:

datasource:

driver-class-name: com.p6spy.engine.spy.P6SpyDriver

url: jdbc:p6spy:mysql://localhost:3306/triumphxxtop?useUnicode&#61;true&useSSL&#61;false&characterEncoding&#61;utf8&serverTimezone&#61;UTC

username: root

password: root

引入配置文件

42bc4bcb2d02924a5b0d170cb67ccb1c.png

项目设计思路&#xff0c;在项目启动的时候&#xff0c;将今日的热卖商品数据缓存到redis中&#xff0c;代码如下:

/**

* &#64;author:triumphxx

* &#64;Date:2020/5/16

* &#64;Time:7:40 上午

* &#64;微信公众号&#xff1a;北漂码农有话说

* &#64;desc:系统启动加载类

**/

&#64;Component

public class ContextStartUp implements ApplicationRunner {

&#64;Autowired

SellService sellService;

/**

* 服务启动是加载执行的的方法

* 将每天热卖的商品进行展示

* &#64;param args

* &#64;throws Exception

*/

&#64;Override

public void run(ApplicationArguments args) throws Exception {

sellService.initGoodsSellTop();

}

}

核心代码如下&#xff0c;每一步都有详细的说明。

&#64;Autowired

GoodsService goodsService;

&#64;Autowired

RedisUtil redisUtil;

&#64;Autowired

com.triumphxx.util.DateUtil dateUtil;

&#64;Override

public void initGoodsSellTop() {

//获取当天内销售量大于80的商品id和销售记录id

List sells &#61; this.list(new QueryWrapper()

.ge("sell_num",80)

.ge("sell_date", DateUtil.format(new Date(),"yyyy-MM-dd"))

.select("goods_id","sell_num")

);

List goodsVos &#61; new ArrayList<>();

for (Sell sell : sells) {

//1、根据销售量大于80的销售记录查询出货物的信息

GoodsVo goods &#61; goodsService.selectSellTop(new QueryWrapper().eq("g.goods_id",sell.getGoodsId())

.eq("s.sell_date",DateUtil.format(new Date(),"yyyy-MM-dd")));

//2、将销售货物一天的销售的数量进行数据缓存

redisUtil.zSet(Constants.REDIS_KEY.GOODS_TOP_KEY&#43;goods.getGoodsId(),goods.getGoodsId(),goods.getSellNum());

//设置过期时间 当天有效

//0点的时间减去现在的时间换算层毫秒数

Long expireTime &#61; dateUtil.initDateByDay()-DateUtil.currentSeconds();

redisUtil.expire(Constants.REDIS_KEY.GOODS_TOP_KEY&#43;goods.getGoodsId(),expireTime);

//同时缓存一下货物的基本信息 货物id 货物名称 销售货物数量

this.hasCacheGoods(goods,expireTime);

goodsVos.add(goods);

}

//做并集

this.zuionOneDayTop(goodsVos);

}

/**

*合并当天热卖榜

*/

private void zuionOneDayTop(List goodsVos) {

List otherKeys &#61; new ArrayList<>();

for (GoodsVo goodsVo : goodsVos) {

String temp &#61; Constants.REDIS_KEY.GOODS_TOP_KEY &#43;goodsVo.getGoodsId();

otherKeys.add(temp);

}

redisUtil.zUnionAndStore(Constants.REDIS_KEY.GOODS_TOP_KEY,

otherKeys,Constants.REDIS_KEY.GOODS_ONE_DAY_RANK);

}

/**

* 缓存货物的基本信息

* &#64;param goods

* &#64;param expireTime

*/

private void hasCacheGoods(GoodsVo goods, Long expireTime) {

//构造货物基本信息key

String goodsKey &#61;Constants.REDIS_KEY.GOODS_KEY&#43;goods.getGoodsId();

boolean isKey &#61; redisUtil.hasKey(goodsKey);

if (!isKey){

redisUtil.hset(goodsKey,Constants.REDIS_KEY.GOODS_KEY_ID,goods.getGoodsId(),expireTime);

redisUtil.hset(goodsKey,Constants.REDIS_KEY.GOODS_KEY_NAME,goods.getGoodsName(),expireTime);

redisUtil.hset(goodsKey,Constants.REDIS_KEY.GOODS_KEY_SELL_NUM,goods.getSellNum(),expireTime);

}

}

代码中设计的常量类如下

/**

* &#64;author:triumphxx

* &#64;Date:2020/5/16

* &#64;Time:9:43 上午

* &#64;微信公众号&#xff1a;北漂码农有话说

* &#64;desc:常量类

**/

public class Constants {

public static class REDIS_KEY {

/**

* 货物销量key 每天某一个货物的销售量

*/

public static final String GOODS_TOP_KEY&#61; "goods:rank:";

/**

* 货物的基本信息key

*/

public static final String GOODS_KEY&#61; "goods:";

/**

* 货物id

*/

public static final String GOODS_KEY_ID&#61; "goods:id:";

/**

* 货物名称

*/

public static final String GOODS_KEY_NAME&#61; "goods:name:";

/**

* 货物销售数量

*/

public static final String GOODS_KEY_SELL_NUM&#61; "goods:sellnum:";

/**

* 每日销售并集后的key

*/

public static final String GOODS_ONE_DAY_RANK&#61; "oneday:rank";

}

}

项目中涉及的其他技术点比如&#xff1a;自定义标签等有机会专题讨论

项目中的具体细节请移步GitHub分析相关源码

项目最终效果如图

bb5025828c32364915b662010dad5bf6.png

本文的案例&#xff0c;本被人已经上传到 GitHub上了&#xff0c;地址&#xff1a;https://github.com/triumphxx/triumphxxtop

如果觉得笔者的内容对你有用&#xff0c;请关注微信公众号&#xff0c;欢迎点赞评论。

d00314659dcfe5fbfb6d6168e7b218ce.png



推荐阅读
  • Redis底层数据结构之压缩列表的介绍及实现原理
    本文介绍了Redis底层数据结构之压缩列表的概念、实现原理以及使用场景。压缩列表是Redis为了节约内存而开发的一种顺序数据结构,由特殊编码的连续内存块组成。文章详细解释了压缩列表的构成和各个属性的含义,以及如何通过指针来计算表尾节点的地址。压缩列表适用于列表键和哈希键中只包含少量小整数值和短字符串的情况。通过使用压缩列表,可以有效减少内存占用,提升Redis的性能。 ... [详细]
  • 本文介绍了Redis的基础数据结构string的应用场景,并以面试的形式进行问答讲解,帮助读者更好地理解和应用Redis。同时,描述了一位面试者的心理状态和面试官的行为。 ... [详细]
  • 本文介绍了lua语言中闭包的特性及其在模式匹配、日期处理、编译和模块化等方面的应用。lua中的闭包是严格遵循词法定界的第一类值,函数可以作为变量自由传递,也可以作为参数传递给其他函数。这些特性使得lua语言具有极大的灵活性,为程序开发带来了便利。 ... [详细]
  • 本文介绍了Python高级网络编程及TCP/IP协议簇的OSI七层模型。首先简单介绍了七层模型的各层及其封装解封装过程。然后讨论了程序开发中涉及到的网络通信内容,主要包括TCP协议、UDP协议和IPV4协议。最后还介绍了socket编程、聊天socket实现、远程执行命令、上传文件、socketserver及其源码分析等相关内容。 ... [详细]
  • 搭建Windows Server 2012 R2 IIS8.5+PHP(FastCGI)+MySQL环境的详细步骤
    本文详细介绍了搭建Windows Server 2012 R2 IIS8.5+PHP(FastCGI)+MySQL环境的步骤,包括环境说明、相关软件下载的地址以及所需的插件下载地址。 ... [详细]
  • Mac OS 升级到11.2.2 Eclipse打不开了,报错Failed to create the Java Virtual Machine
    本文介绍了在Mac OS升级到11.2.2版本后,使用Eclipse打开时出现报错Failed to create the Java Virtual Machine的问题,并提供了解决方法。 ... [详细]
  • 在说Hibernate映射前,我们先来了解下对象关系映射ORM。ORM的实现思想就是将关系数据库中表的数据映射成对象,以对象的形式展现。这样开发人员就可以把对数据库的操作转化为对 ... [详细]
  • 本文介绍了Oracle数据库中tnsnames.ora文件的作用和配置方法。tnsnames.ora文件在数据库启动过程中会被读取,用于解析LOCAL_LISTENER,并且与侦听无关。文章还提供了配置LOCAL_LISTENER和1522端口的示例,并展示了listener.ora文件的内容。 ... [详细]
  • 模板引擎StringTemplate的使用方法和特点
    本文介绍了模板引擎StringTemplate的使用方法和特点,包括强制Model和View的分离、Lazy-Evaluation、Recursive enable等。同时,还介绍了StringTemplate语法中的属性和普通字符的使用方法,并提供了向模板填充属性的示例代码。 ... [详细]
  • 安装mysqlclient失败解决办法
    本文介绍了在MAC系统中,使用django使用mysql数据库报错的解决办法。通过源码安装mysqlclient或将mysql_config添加到系统环境变量中,可以解决安装mysqlclient失败的问题。同时,还介绍了查看mysql安装路径和使配置文件生效的方法。 ... [详细]
  • 本文分享了一个关于在C#中使用异步代码的问题,作者在控制台中运行时代码正常工作,但在Windows窗体中却无法正常工作。作者尝试搜索局域网上的主机,但在窗体中计数器没有减少。文章提供了相关的代码和解决思路。 ... [详细]
  • 本文讨论了如何优化解决hdu 1003 java题目的动态规划方法,通过分析加法规则和最大和的性质,提出了一种优化的思路。具体方法是,当从1加到n为负时,即sum(1,n)sum(n,s),可以继续加法计算。同时,还考虑了两种特殊情况:都是负数的情况和有0的情况。最后,通过使用Scanner类来获取输入数据。 ... [详细]
  • 本文详细介绍了PHP中与URL处理相关的三个函数:http_build_query、parse_str和查询字符串的解析。通过示例和语法说明,讲解了这些函数的使用方法和作用,帮助读者更好地理解和应用。 ... [详细]
  • 知识图谱——机器大脑中的知识库
    本文介绍了知识图谱在机器大脑中的应用,以及搜索引擎在知识图谱方面的发展。以谷歌知识图谱为例,说明了知识图谱的智能化特点。通过搜索引擎用户可以获取更加智能化的答案,如搜索关键词"Marie Curie",会得到居里夫人的详细信息以及与之相关的历史人物。知识图谱的出现引起了搜索引擎行业的变革,不仅美国的微软必应,中国的百度、搜狗等搜索引擎公司也纷纷推出了自己的知识图谱。 ... [详细]
  • 本文介绍了一道网络流题目hdu4888 Redraw Beautiful Drawings的解题思路。题目要求以行和列作为结点建图,并通过最大流算法判断是否有解以及是否唯一。文章详细介绍了建图和算法的过程,并强调在dfs过程中要进行回溯。 ... [详细]
author-avatar
mobiledu2502880317
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有