亚洲国产日韩欧美一区二区三区,精品亚洲国产成人av在线,国产99视频精品免视看7,99国产精品久久久久久久成人热,欧美日韩亚洲国产综合乱

目錄
首頁(yè) Java Java基礎(chǔ) 便捷的統(tǒng)計(jì)訂單收益(一)

便捷的統(tǒng)計(jì)訂單收益(一)

Oct 21, 2020 pm 05:18 PM

java基礎(chǔ)教學(xué)專欄帶大家了解如何便捷的統(tǒng)計(jì)訂單效益。

便捷的統(tǒng)計(jì)訂單收益(一)

引言

#統(tǒng)計(jì)訂單收益是做電商類型的APP老生常談的問(wèn)題.常規(guī)需求大致有用戶收益日?qǐng)?bào)/月報(bào)/年報(bào).這些報(bào)表型的數(shù)據(jù)對(duì)錶設(shè)計(jì)和程序設(shè)計(jì)有著不小的挑戰(zhàn).常規(guī)的聚合查詢語(yǔ)句的查詢時(shí)間會(huì)隨著收益表資料日漸龐大而逐漸變長(zhǎng)。這時(shí)候就需要思考如何設(shè)計(jì)收益表可以更有效率的查詢?怎樣的設(shè)計(jì)才可以讓統(tǒng)計(jì)收益變得簡(jiǎn)單?

需求

#效果圖

具體需求

  • 收益類型分為:自購(gòu)訂單收益,分享訂單收益,分銷收益,活動(dòng)收益
  • 統(tǒng)計(jì)當(dāng)日收益,當(dāng)月收益
  • 根據(jù)篩選的時(shí)間統(tǒng)計(jì)出時(shí)間段的收益.

思考

#設(shè)計(jì)想法

#訂單表是肯定需要的.在寫入或修改訂單表的時(shí)候同步寫入修改收益表.只有自購(gòu)和分享訂單會(huì)記錄到訂單表中,分銷以及活動(dòng)贈(zèng)送收益只在特殊業(yè)務(wù)中寫入收益表.再以日為維度,建立一張用戶收益日?qǐng)?bào)表.單行記錄寫入用戶當(dāng)天收益狀況.降低

查詢用戶日/月/年收益統(tǒng)計(jì)時(shí)的資料量.以單一使用者為例,透過(guò)分割使用者一個(gè)月只會(huì)產(chǎn)生最多###31###條資料.屬於可控製成長(zhǎng)速度.如果沿用損益表,因?yàn)閾p益表的數(shù)據(jù)量跟用戶下單的數(shù)量一一對(duì)應(yīng),如果用戶下單量多那麼表會(huì)非常龐大.在前期用戶量初見(jiàn)增長(zhǎng)時(shí),可用此方法規(guī)避大的數(shù)據(jù)量統(tǒng)計(jì),後期如果用戶量增大導(dǎo)致日?qǐng)?bào)表資料變多可以再考慮分錶.###

可見(jiàn)問(wèn)題

  • #同步收益日?qǐng)?bào)表的時(shí)機(jī)問(wèn)題,因?yàn)樵居唵蔚牟僮骶秃苎}雜需要同步寫入收益和計(jì)算寫入收益日?qǐng)?bào)資料,程式碼耦合度太高.有沒(méi)有什麼方法透過(guò)收益表異構(gòu)出收益日?qǐng)?bào)呢?
  • 雖然收益被寫入到了日?qǐng)?bào)表中,但是要滿足效果圖要求的效果,可能需要多次查詢SQL語(yǔ)句,有沒(méi)有辦法在不影響程序效率的情況下盡量少些一些聚合SQL呢?

實(shí)作

總結(jié)出上面這些問(wèn)題.我開始了資料收集.最終採(cǎi)用canal RocketMQ做為異質(zhì)方案.

#技術(shù)堆疊

簡(jiǎn)單介紹一下這兩款技術(shù)框架:

  • canal:主要用途是基於MySQL 資料庫(kù)增量日誌解析,提供增量資料訂閱和消耗
  • RocketMQ:一款開源的分散式訊息系統(tǒng),基於高可用分散式叢集技術(shù),提供低延時(shí)的、高可靠的訊息發(fā)布與訂閱服務(wù)。

註:我用的aliyun的全家桶,MQ和mysql都是阿里雲(yún)的,如果是自建伺服器的可能有區(qū)別,我在後面盡量標(biāo)出

方案流程

  1. #在寫入或修改收益表的同時(shí)透過(guò)canal監(jiān)控mysql收益表的binlog日誌.
  2. #canal檢測(cè)到變更,組裝變更的JSON封包,發(fā)送RocketMQ中事先定義好的TOPIC.
  3. 程式消費(fèi)該TOPIC,異質(zhì)收益日?qǐng)?bào)表.

canal設(shè)定部分

canal的安裝請(qǐng)參考官方文檔 解壓縮後可得到一個(gè)canal資料夾,包含三個(gè)目錄

  • bin:存放啟動(dòng)重啟腳本
  • #conf:存放核心設(shè)定檔
  • lib:存放核心jar套件

我們需要專注於conf資料夾裡的conf/canal.properties核心設(shè)定檔以及conf/example/instance.properties單一監(jiān)控節(jié)點(diǎn)設(shè)定檔

conf/canal.properties

#
# tcp, kafka, RocketMQ,這里默認(rèn)是tcp讀取模式,采用RocketMQ需要將其改變?yōu)镽ocketMQ模式
canal.serverMode = RocketMQ
# 如果是aliyun的RocketMQ需要配置以下兩個(gè)KEY,ak/sk
canal.aliyun.accessKey =xxxxxxx
canal.aliyun.secretKey =xxxxxxx
# 監(jiān)控的節(jié)點(diǎn)名稱.這個(gè)默認(rèn)就是example如果有多節(jié)點(diǎn)可以逗號(hào)隔開,如下方的例子
canal.destinations = example,sign
# 如果是aliyun的RocketMQ需要修改canal.mq.accessChannel為cloud默認(rèn)為local
canal.mq.accessChannel = cloud
#MQ的地址,需要注意這里是不帶http://,但是需要帶端口號(hào)
canal.mq.servers = 
#rocketmq實(shí)例id
canal.mq.namespace =

##conf/example/instance. properties
#mysql地址
canal.instance.master.address=
#以下兩個(gè)參數(shù)需要在開啟數(shù)據(jù)庫(kù)binlog日志后得到,在數(shù)據(jù)庫(kù)查詢界面輸入查詢語(yǔ)句`show master status`,canal.instance.master.journal.name對(duì)應(yīng)File參數(shù),canal.instance.master.position對(duì)應(yīng)Position參數(shù)
canal.instance.master.journal.name=
canal.instance.master.position=
#數(shù)據(jù)庫(kù)的賬號(hào)密碼
canal.instance.dbUsername=
canal.instance.dbPassword=
#需要監(jiān)控變動(dòng)的表
canal.instance.filter.regex=xxx.t_user_order,xxx.t_user_cash_out
#定義發(fā)送的mq生產(chǎn)組
canal.mq.producerGroup = 
#定義發(fā)送到mq的指定主題
canal.mq.topic=

註:監(jiān)視器表的書寫規(guī)則格式參考監(jiān)控表書寫規(guī)則

這時(shí)候會(huì)發(fā)現(xiàn)canal目錄中多了一個(gè)log檔,進(jìn)入可以看到canal主日誌檔和example節(jié)點(diǎn)啟動(dòng)日誌.

canal日志中出現(xiàn)
 the canal server is running now ......
example日志中出現(xiàn)
 init table filter : ^tablename
 xxxxxxxxx , the next step is binlog dump

表示你已經(jīng)成功了一大步,canal監(jiān)控已正常運(yùn)作.

RocketMQ部分

如果用的aliyun的RocketMQ,配置代碼部分直接可參考文檔 自建的RocketMQ也可參照簡(jiǎn)單的消費(fèi)例子監(jiān)控對(duì)應(yīng)的TOPIC即可 消費(fèi)Canal發(fā)來(lái)的數(shù)據(jù),格式如下:

{
    "data":[
        {
            //單個(gè)修改后表數(shù)據(jù),如果同一時(shí)間有多個(gè)表變動(dòng)會(huì)有多個(gè)該JSON對(duì)象        }
    ],
    "database":"監(jiān)控的表所在數(shù)據(jù)庫(kù)",
    "es":表變動(dòng)時(shí)間,
    "id":canal生成的id,
    "isDdl":Boolean類型,表示是否DDL語(yǔ)句,
    "mysqlType":{
        表結(jié)構(gòu)
    },
    "old":如果是修改類型會(huì)填充修改前的值,
    "pkNames":[
        該表的主鍵,如"id"
    ],
    "sql":"執(zhí)行的SQL",
    "sqlType":{
        字段對(duì)應(yīng)的sqlType,一般使用mysqlType即可
    },
    "table":"監(jiān)控的表名",
    "ts":canal記錄發(fā)送時(shí)間,
    "type":"表的修改類型,入INSERT,UPDATE,DELETE"
}

MQ消費(fèi)代碼主要用了反射,映射到對(duì)應(yīng)的表

//這里的body就是Canal發(fā)來(lái)的數(shù)據(jù)
public Action process(String body) {
        boolean result = Boolean.FALSE;
        JSONObject data = JSONObject.parseObject(body);
        log.info("數(shù)據(jù)庫(kù)操作日志記錄:data:{}",data.toString());
        Class c = null;
        try {
            //這里監(jiān)控了訂單和收益表分別做訂單統(tǒng)計(jì)和收益日?qǐng)?bào)統(tǒng)計(jì)
            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部分轉(zhuǎn)換為反射后的實(shí)體集合
                List list = dataArray.toJavaList(c);
                if (CollUtil.isNotEmpty(list)) {
                    //對(duì)修改和寫入操作分別進(jìn)行邏輯操作
                    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();
        //判斷是哪張表的數(shù)據(jù)
        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: 寫入對(duì)應(yīng)類型的統(tǒng)計(jì)表
     * @author: chenyunxuan
     */
    private <T> Boolean saveHistory(List<T> orderList) {
        boolean result = Boolean.FALSE;
        Object dataType = orderList.get(0);
        //用instanceof判斷類型進(jìn)入不同的邏輯處理代碼
        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) {
    //循環(huán)收益明細(xì)記錄
    .......
    //通過(guò)創(chuàng)建時(shí)間和用戶id查詢收益日?qǐng)?bào)表中是否有當(dāng)日數(shù)據(jù)
    if(不存在當(dāng)日數(shù)據(jù)){
        //創(chuàng)建當(dāng)日的收益日?qǐng)?bào)表記錄
        .....
    }
    //因?yàn)椴淮嬖诋?dāng)日記錄也會(huì)立即寫入當(dāng)日的空數(shù)據(jù),所以下面的流程都是走更新流程
    //更新當(dāng)日數(shù)據(jù)
    .......
    return Boolean.TRUE;
    }

注:代碼中應(yīng)該多打一些日志,方便產(chǎn)生異常收益數(shù)據(jù)后的校對(duì)

后記

至此一個(gè)基于canal+RocketMQ的收益日?qǐng)?bào)統(tǒng)計(jì)異構(gòu)方案就完成了,下一篇會(huì)圍繞本文提到的第二個(gè)問(wèn)題減少聚合SQL的產(chǎn)生展開.敬請(qǐng)關(guān)注.

相關(guān)免費(fèi)學(xué)習(xí)推薦:java基礎(chǔ)教程

以上是便捷的統(tǒng)計(jì)訂單收益(一)的詳細(xì)內(nèi)容。更多資訊請(qǐng)關(guān)注PHP中文網(wǎng)其他相關(guān)文章!

本網(wǎng)站聲明
本文內(nèi)容由網(wǎng)友自願(yuàn)投稿,版權(quán)歸原作者所有。本站不承擔(dān)相應(yīng)的法律責(zé)任。如發(fā)現(xiàn)涉嫌抄襲或侵權(quán)的內(nèi)容,請(qǐng)聯(lián)絡(luò)admin@php.cn

熱AI工具

Undress AI Tool

Undress AI Tool

免費(fèi)脫衣圖片

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅(qū)動(dòng)的應(yīng)用程序,用於創(chuàng)建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費(fèi)的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費(fèi)的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強(qiáng)大的PHP整合開發(fā)環(huán)境

Dreamweaver CS6

Dreamweaver CS6

視覺(jué)化網(wǎng)頁(yè)開發(fā)工具

SublimeText3 Mac版

SublimeText3 Mac版

神級(jí)程式碼編輯軟體(SublimeText3)

熱門話題

Laravel 教程
1597
29
PHP教程
1488
72