Maison > Java > JavaBase > Statistiques pratiques sur les revenus des commandes (1)

Statistiques pratiques sur les revenus des commandes (1)

coldplay.xixi
Libérer: 2020-10-21 17:22:37
avant
2307 Les gens l'ont consulté

La colonne

Tutoriel de base Java vous montrera comment compter facilement les revenus des commandes.

Statistiques pratiques sur les revenus des commandes (1)

Introduction

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 ?

Exigences

Rendu

Besoins spécifiques

  • Les types de revenus sont divisés en : Revenu des commandes auto-achetées, revenu des commandes partagées, revenu de distribution, revenu d'activité
  • statistiques le revenu du jour, le revenu du mois
  • est calculé en fonction du temps de projection. Revenu au cours de la période.

Penser

Idées de design

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.

Problèmes visibles

  • Le timing de synchronisation du rapport de revenus quotidien est un problème car la commande originale L'opération est très compliquée. Il est compliqué d'écrire les revenus et de calculer et d'écrire simultanément les données sur les revenus quotidiens, et le couplage de code est trop élevé. Existe-t-il un moyen de générer des rapports de revenus quotidiens via l'hétérogénéité du compte de résultat ? 🎜>
    Bien que les revenus soient écrits dans le rapport quotidien, mais pour répondre aux exigences des rendus, il peut être nécessaire d'interroger les instructions SQL plusieurs fois. Existe-t-il un moyen de réduire le nombre d'instructions SQL agrégées sans. affectant l'efficacité du programme ?

Mise en œuvre J'ai résumé les problèmes ci-dessus. a commencé la collecte de données. Finalement, j'ai utilisé +

Comme solution hétérogène.

canalRocketMQ

Pile technologique
  • canal : L'objectif principal est de fournir un abonnement et une consommation de données incrémentielles basés sur l'analyse incrémentielle des journaux de la base de données MySQL
  • RocketMQ : un message distribué open source Le système , basé sur une technologie de cluster distribué à haute disponibilité, fournit des services de publication de messages et d'abonnement à faible latence et hautement fiables.

注:我用的aliyun的全家桶,MQ和mysql都是阿里云的,如果是自建服务器的可能有区别,我在后面尽量标出

Processus de proposition

  1. Surveillez le journal binlog du compte de résultat mysql via canal lors de la rédaction ou de la modification du compte de résultat.
  2. canal détecte le changement et assemble le changez le message JSON, envoyez le TOPIC prédéfini dans RocketMQ.
  3. Le programme consomme le TOPIC, rapport quotidien sur les revenus hétérogènes.

partie configuration du canal

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

  • bin : stocke les scripts de démarrage et de redémarrage
  • conf:存放核心配置文件
  • lib : stocke les packages de jar de base

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

conf/canal.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 =
Copier après la connexion

conf/example/instance.properties

#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=
Copier après la connexion

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

Démarrer

cd /canal/bin
./start.sh
Copier après la connexion

À 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
Copier après la connexion

signifie que vous avez fait un grand pas et que la surveillance du canal est normale.

RocketMQ部分

如果用的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"
}
Copier après la connexion

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;
    }
Copier après la connexion

saveIncomeDaily伪代码

  public synchronized Boolean saveIncomeDaily(List orderList) {
    //循环收益明细记录
    .......
    //通过创建时间和用户id查询收益日报表中是否有当日数据
    if(不存在当日数据){
        //创建当日的收益日报表记录
        .....
    }
    //因为不存在当日记录也会立即写入当日的空数据,所以下面的流程都是走更新流程
    //更新当日数据
    .......
    return Boolean.TRUE;
    }
Copier après la connexion

注:代码中应该多打一些日志,方便产生异常收益数据后的校对

后记

至此一个基于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!

Étiquettes associées:
source:juejin.im
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal