La colonne
Tutoriel de base Java vous montrera comment compter facilement les revenus des commandes.
Le revenu des commandes statistiques est un e- entreprise de commerce Il s'agit d'un problème courant dans les applications. Les exigences générales incluent généralement les avantages pour les utilisateurs 日报/月报/年报
Ces données de type rapport posent un grand défi à la conception et à la programmation des tables. Le temps d'interrogation des déclarations 聚合查询
régulières augmentera avec les revenus. données de relevé. Elles sont énormes et s'allongent progressivement. À l'heure actuelle, nous devons réfléchir à la manière de concevoir le tableau des revenus afin qu'il puisse être interrogé plus efficacement ? Quel type de conception peut simplifier les revenus statistiques ?
Le tableau des commandes est absolument nécessaire. Lors de la rédaction ou de la modification du tableau des commandes, écrivez et modifiez simultanément le tableau des revenus. Seules les commandes d'auto-achat et de partage seront enregistrées dans le tableau des commandes, ainsi que les cadeaux de distribution et d'événement. les revenus ne seront enregistrés que dans le tableau des commandes. Écrivez le compte de résultat dans l'entreprise spéciale. Utilisez ensuite le jour comme dimension pour créer un utilisateur 收益日报表
Écrivez un enregistrement sur une seule ligne des revenus de l'utilisateur pour la journée. Interrogez la quantité de données lors de l'interrogation des statistiques de revenus quotidiens/mois/années de l'utilisateur. Utilisez une seule ligne. Par exemple, en divisant les utilisateurs, un maximum de 降低
éléments de données seront générés en un mois. Si le compte de résultat est utilisé, car la quantité de données dans le compte de résultat correspond au nombre de commandes passées par l'utilisateur, si l'utilisateur passe Si le nombre de commandes est important, le tableau sera très grand au début. lorsque le nombre d'utilisateurs commence à augmenter, cette méthode peut être utilisée pour éviter les statistiques de données volumineuses. À un stade ultérieur, si le nombre d'utilisateurs augmente et que les données du rapport quotidien deviennent plus volumineuses, vous pouvez envisager de diviser le tableau 31
.
canal
RocketMQ
注:我用的aliyun的全家桶,MQ和mysql都是阿里云的,如果是自建服务器的可能有区别,我在后面尽量标出
Veuillez vous référer à la documentation officielle pour l'installation du canal Après décompression, vous obtiendrez un dossier canal, contenant trois répertoires
conf:存放核心配置文件
Nous devons nous concentrer sur le fichier de configuration principal conf/canal.properties dans le dossier conf et sur le fichier de configuration du nœud de surveillance unique conf/example/instance.properties
# tcp, kafka, RocketMQ,这里默认是tcp读取模式,采用RocketMQ需要将其改变为RocketMQ模式 canal.serverMode = RocketMQ # 如果是aliyun的RocketMQ需要配置以下两个KEY,ak/sk canal.aliyun.accessKey =xxxxxxx canal.aliyun.secretKey =xxxxxxx # 监控的节点名称.这个默认就是example如果有多节点可以逗号隔开,如下方的例子 canal.destinations = example,sign # 如果是aliyun的RocketMQ需要修改canal.mq.accessChannel为cloud默认为local canal.mq.accessChannel = cloud #MQ的地址,需要注意这里是不带http://,但是需要带端口号 canal.mq.servers = #rocketmq实例id canal.mq.namespace =
#mysql地址 canal.instance.master.address= #以下两个参数需要在开启数据库binlog日志后得到,在数据库查询界面输入查询语句`show master status`,canal.instance.master.journal.name对应File参数,canal.instance.master.position对应Position参数 canal.instance.master.journal.name= canal.instance.master.position= #数据库的账号密码 canal.instance.dbUsername= canal.instance.dbPassword= #需要监控变动的表 canal.instance.filter.regex=xxx.t_user_order,xxx.t_user_cash_out #定义发送的mq生产组 canal.mq.producerGroup = #定义发送到mq的指定主题 canal.mq.topic=
Remarque : Pour le format des règles d'écriture de la table de surveillance, se référer aux règles d'écriture de la table de surveillance
cd /canal/bin ./start.sh
À ce stade, vous constaterez qu'il y a un fichier journal supplémentaire dans le répertoire du canal. Entrez-le et vous pourrez voir le fichier journal principal du canal et l'exemple de journal de démarrage du nœud. .
canal日志中出现 the canal server is running now ...... example日志中出现 init table filter : ^tablename xxxxxxxxx , the next step is binlog dump
signifie que vous avez fait un grand pas et que la surveillance du canal est normale.
如果用的aliyun的RocketMQ,配置代码部分直接可参考文档 自建的RocketMQ也可参照简单的消费例子监控对应的TOPIC即可 消费Canal发来的数据,格式如下:
{ "data":[ { //单个修改后表数据,如果同一时间有多个表变动会有多个该JSON对象 } ], "database":"监控的表所在数据库", "es":表变动时间, "id":canal生成的id, "isDdl":Boolean类型,表示是否DDL语句, "mysqlType":{ 表结构 }, "old":如果是修改类型会填充修改前的值, "pkNames":[ 该表的主键,如"id" ], "sql":"执行的SQL", "sqlType":{ 字段对应的sqlType,一般使用mysqlType即可 }, "table":"监控的表名", "ts":canal记录发送时间, "type":"表的修改类型,入INSERT,UPDATE,DELETE" }
MQ消费代码主要用了反射,映射到对应的表
//这里的body就是Canal发来的数据 public Action process(String body) { boolean result = Boolean.FALSE; JSONObject data = JSONObject.parseObject(body); log.info("数据库操作日志记录:data:{}",data.toString()); Class c = null; try { //这里监控了订单和收益表分别做订单统计和收益日报统计 c = Class.forName(getClassName(data.getString("table"))); } catch (ClassNotFoundException e) { log.error("error {}",e); } if (null != c) { JSONArray dataArray = data.getJSONArray("data"); if (dataArray != null) { //把获取到的data部分转换为反射后的实体集合 List list = dataArray.toJavaList(c); if (CollUtil.isNotEmpty(list)) { //对修改和写入操作分别进行逻辑操作 String type = data.getString("type"); if ("UPDATE".equals(type)) { result = uppHistory(list); } else if ("INSERT".equals(type)) { result = saveHistory(list); } } } } return result ? Action.CommitMessage : Action.ReconsumeLater; } /** * @description: 获取反射ClassName * @author: chenyunxuan */ private String getClassName(String tableName) { StringBuilder sb = new StringBuilder(); //判断是哪张表的数据 if (tableName.equals("t_user_income_detail")) { sb.append("cn.mc.core.model.order"); } else if (tableName.equals("t_user_cash_out")) { sb.append("cn.mc.sync.model"); } String className = StrUtil.toCamelCase(tableName).substring(1); return sb.append(".").append(className).toString(); } /** * @description: 写入对应类型的统计表 * @author: chenyunxuan */ private <T> Boolean saveHistory(List<T> orderList) { boolean result = Boolean.FALSE; Object dataType = orderList.get(0); //用instanceof判断类型进入不同的逻辑处理代码 if (dataType instanceof TUserIncomeDetail) { result = userOrderHistoryService.saveIncomeDaily(orderList); } else if (dataType instanceof UserCashOut) { result = userCashOutHistoryService.delSaveHistoryList(orderList); } return result; }
saveIncomeDaily伪代码
public synchronized Boolean saveIncomeDaily(List orderList) { //循环收益明细记录 ....... //通过创建时间和用户id查询收益日报表中是否有当日数据 if(不存在当日数据){ //创建当日的收益日报表记录 ..... } //因为不存在当日记录也会立即写入当日的空数据,所以下面的流程都是走更新流程 //更新当日数据 ....... return Boolean.TRUE; }
注:代码中应该多打一些日志,方便产生异常收益数据后的校对
至此一个基于canal
+RocketMQ
的收益日报统计异构方案就完成了,下一篇会围绕本文提到的第二个问题减少聚合SQL的产生展开.敬请关注.
相关免费学习推荐:java基础教程
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!