成人无码视频,亚洲精品久久久久av无码,午夜精品久久久久久毛片,亚洲 中文字幕 日韩 无码

資訊專欄INFORMATION COLUMN

賬戶變動(dòng)合并提交方案

MoAir / 3123人閱讀

摘要:起因及介紹在早期的賬戶系統(tǒng)中,但凡有賬戶變動(dòng),就會(huì)執(zhí)行一次數(shù)據(jù)庫(kù)操作。這時(shí),在一次處理過(guò)程中,合并同一個(gè)賬戶的所有操作,最后只提交一次,就能帶來(lái)很大的優(yōu)化空間。根據(jù)業(yè)務(wù)需要,進(jìn)行增減轉(zhuǎn)賬凍結(jié)解凍操作。

起因及介紹

在早期的賬戶系統(tǒng)中,但凡有賬戶變動(dòng),就會(huì)執(zhí)行一次數(shù)據(jù)庫(kù)操作。這樣在有復(fù)雜一些業(yè)務(wù)操作的時(shí)候,例如單筆交易涉及多個(gè)用戶多個(gè)費(fèi)用的資金劃撥,一個(gè)事務(wù)內(nèi)操作數(shù)據(jù)庫(kù)幾十次也就大量的存在。而觀察這樣的場(chǎng)景,其本質(zhì)可能只涉及少數(shù)幾方的賬戶。
這時(shí),在一次處理過(guò)程中,合并同一個(gè)賬戶的所有操作,最后只提交一次,就能帶來(lái)很大的優(yōu)化空間。

處理方法

1. 初始化一個(gè)收集器ExecuteParam,用來(lái)存放有變動(dòng)的賬戶、待新增的資金記錄、待處理的凍結(jié)數(shù)據(jù)和待新增的凍結(jié)記錄。

final ExecuteParam param = ExecuteParam.instance();

public class ExecuteParam {
    private final Map cache = Maps.newHashMap();
    private final List financeLogs = Lists.newArrayList();
    private final Map freezeRecords = Maps.newHashMap();
    private final List freezeHistorys = Lists.newArrayList();

    public static ExecuteParam instance() {
        return new ExecuteParam();
    }

    public Map getCache() {
        return cache;
    }

    public List getFinanceLogs() {
        return financeLogs;
    }

    public Map getFreezeRecords() {
        return freezeRecords;
    }

    public List getFreezeHistorys() {
        return freezeHistorys;
    }
}

2. 根據(jù)業(yè)務(wù)需要,進(jìn)行增、減、轉(zhuǎn)賬、凍結(jié)、解凍操作。

public interface FundTransactionService {
    /** 調(diào)增 */
    void addCredit(TransactionCommandParam command, final ExecuteParam param);

    /** 調(diào)減 */
    void addDebit(TransactionCommandParam command, final ExecuteParam param);

    /** 轉(zhuǎn)賬 */
    void addTransfer(TransactionCommandParam command, final ExecuteParam param);

    /** 凍結(jié) */
    String addFreeze(TransactionCommandParam command, final ExecuteParam param);

    /** 解凍 */
    BigDecimal addUnfreeze(TransactionCommandParam command, final ExecuteParam param);

    /** 更新DB */
    void execute(String proofId, ExecuteParam param);
}

public static TransactionCommandParam createTransfer(...);

public static TransactionCommandParam createFreeze(...);

public static TransactionCommandParam createUnfreeze(...);

public static TransactionCommandParam createCredit(...);

public static TransactionCommandParam createDebit(...);

3. 所有資金操作在底層都按照:校驗(yàn)操作類型->修改賬戶余額->資金記錄的流程執(zhí)行

@Override
public void addCredit(TransactionCommandParam command, final ExecuteParam param) {
    /** 1.校驗(yàn) */

    /** 2.調(diào)賬 */
    FinanceAccount receiverFa = credit(command.getReceiverOwnerId(), command.getReceiverRoleId(), command.getAmount(), param.getCache());

    /** 3.資金記錄 */
    param.getFinanceLogs().add(...);
}

4. 其中修改賬戶余額的方法,會(huì)先嘗試從ExecuteParam中查找該賬戶是否已經(jīng)被操作過(guò),如果沒(méi)有才查詢一次DB。這樣就確保了同一個(gè)賬戶在一次處理過(guò)程中,無(wú)論有多少資金操作,只會(huì)查詢一次DB。

private FinanceAccount credit(Long ownerId, Long roleId, BigDecimal amount, Map cache) {
    final String cacheKey = getCacheKey(ownerId, roleId);
    FinanceAccount fa = cache.get(cacheKey);
    if (fa == null) {
        // 此處只查詢一次DB
        fa = getFinanceAccount(ownerId, roleId);
        cache.put(cacheKey, fa);
    }

    // 調(diào)增:
    fa.credit(amount);

    return fa;
}

5. 當(dāng)所有業(yè)務(wù)操作完成之后,一次性提交本次處理過(guò)程中的所有賬戶

fundTransactionService.execute(proof.getProofId(), param);

@Override
public void execute(String proofId, ExecuteParam param) {
    /** FinanceAccount統(tǒng)一更新 */
    for (FinanceAccount account : param.getCache().values()) {
        account.setProofId(proofId);

        // 熱點(diǎn)賬戶延遲更新
        if (isHotAccount(account.getId())) {
            continue;
        }

        // DB update
        this.updateAccount(account);
        logger.info("賬戶更新[{}]", account);
    }

    /** FinanceLog統(tǒng)一批量記錄 */
    financeLogDao.addFinanceLog(param.getFinanceLogs());

    /** 凍結(jié)記錄統(tǒng)一批量更新 */
    for (AccFundManagementRecord freezeRecord : param.getFreezeRecords().values()) {
        if (freezeRecord.getId() != null) {
            // DB update
        } else {
            // DB insert
        }
        logger.info(LoggerUtil.createInfoLog("execute","凍結(jié)記錄[{}]"), freezeRecord);
    }

    /** 凍結(jié)歷史統(tǒng)一批量更新 */
    for (AccFundManagementHistory history : param.getFreezeHistorys()) {
        // DB insert
    }
}
總結(jié)和思考

這次優(yōu)化不僅大幅減少了數(shù)據(jù)庫(kù)的負(fù)擔(dān),而且也因?yàn)閿?shù)據(jù)庫(kù)訪問(wèn)次數(shù)少了,處理速度也快了(例如還款,原先的處理時(shí)間約為1到2s,優(yōu)化后的處理時(shí)間約為40ms)。處理速度快了,使用樂(lè)觀鎖控制的并發(fā)異常也相應(yīng)減少了。

另外值得思考的地方是,在第一步初始化收集器ExecuteParam的時(shí)候,將所有容器都創(chuàng)建出來(lái)了,并不是所有業(yè)務(wù)都會(huì)用到全部的容器,這里是否有必要?

我的想法是讓步于開(kāi)發(fā)便利性。
誠(chéng)然是可以根據(jù)不同的場(chǎng)景有選擇性的初始化相應(yīng)的容器,但是這樣開(kāi)發(fā)人員在使用的時(shí)候需要思考的更多,需要做選擇,不夠簡(jiǎn)單明了。而且省去一兩個(gè)容器的初始化帶來(lái)的好處可以并不大。

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://m.hztianpu.com/yun/77292.html

相關(guān)文章

  • 熱點(diǎn)賬戶解決方案

    摘要:全局熱點(diǎn)賬戶平臺(tái)支出賬戶平臺(tái)收入賬戶過(guò)渡賬戶。。那么親,這和熱點(diǎn)賬戶沒(méi)關(guān)系,即使你查詢一個(gè)非常普通的賬戶,碰巧該賬戶同時(shí)在更新,你也查不準(zhǔn)。。 問(wèn)題描述 在某一瞬間,單個(gè)賬戶集中的發(fā)生資金變動(dòng),若不加控制,其賬戶余額會(huì)因發(fā)生臟讀、覆蓋更新等情況而錯(cuò)誤記錄。如果簡(jiǎn)單的以悲觀鎖、樂(lè)觀鎖的方式限制,雖然不會(huì)發(fā)生數(shù)據(jù)錯(cuò)誤,但會(huì)造成服務(wù)不可用(該賬戶的更新請(qǐng)求全部失敗)。而請(qǐng)求重試、再次網(wǎng)絡(luò)通信...

    MycLambert 評(píng)論0 收藏0
  • 【強(qiáng)烈推薦】程序猿開(kāi)發(fā)工具(第二期)

    摘要:這允許開(kāi)發(fā)人員以邏輯區(qū)間建立并提交變動(dòng),以防止當(dāng)部分提交成功時(shí)出現(xiàn)的問(wèn)題納入版本控管的元數(shù)據(jù)每一個(gè)文件與目錄都附有一組屬性關(guān)鍵字并和屬性值相關(guān)聯(lián)。 代碼管理 Git...

    KevinYan 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

閱讀需要支付1元查看
<