成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

一篇學(xué)會(huì)資源庫(kù)Repository的性能優(yōu)化

開(kāi)發(fā) 前端
本篇介紹如何通過(guò)快照+diff的方式優(yōu)化資源庫(kù)的性能,之所有能這樣做是因?yàn)槊總€(gè)業(yè)務(wù)用例都需要先通過(guò)資源庫(kù)獲取到聚合根,最后也需要通過(guò)資源庫(kù)持久化聚合根。

[[403149]]

在DDD中,聚合根需通過(guò)資源庫(kù)(Repository)持久化,資源庫(kù)將聚合根的存儲(chǔ)與存儲(chǔ)中間件(Mysql、ElasticSearch、MonogoDB等)解耦,我們可以根據(jù)聚合的業(yè)務(wù)特性決定選擇關(guān)系型數(shù)據(jù)庫(kù)還是非關(guān)系型數(shù)據(jù)庫(kù)存儲(chǔ)聚合根。

很多讀者可能還存在疑問(wèn),為什么資源庫(kù)只提供一個(gè)save方法持久化聚合根。原因是在DDD中,資源庫(kù)是聚合根的容器,但并不限制容器是什么做的,也就是前面說(shuō)的與底層解耦。如果容器是Key-value數(shù)據(jù)庫(kù)做的,是不支持update某個(gè)字段的,并且inset和update是不區(qū)分的。資源庫(kù)與DAO不同,資源庫(kù)只是向領(lǐng)域模型提供聚合根以及持久化聚合根。

如果我們選擇關(guān)系型數(shù)據(jù)庫(kù)作為聚合根的容器,那么在存儲(chǔ)聚合根時(shí)可能就需要將聚合根以及聚合根下的實(shí)體拆分到多個(gè)表存儲(chǔ),這就可能導(dǎo)致每次save聚合根都需要執(zhí)行多條update語(yǔ)句,即便聚合根下的實(shí)體并沒(méi)有發(fā)生任何的改變,即便只是聚合根修改了一個(gè)字段(值對(duì)象),因此會(huì)嚴(yán)重影響到應(yīng)用的性能。

為解決選擇關(guān)系數(shù)據(jù)庫(kù)作為聚合根容器導(dǎo)致的性能問(wèn)題,我們需要付出額外的努力,如用內(nèi)存快照去判斷每次save聚合根只需要更新哪些表。

基于每個(gè)業(yè)務(wù)用例都需要通過(guò)資源庫(kù)獲取聚合根最后也通過(guò)資源庫(kù)持久化聚合根的特性,我們可以在獲取聚合根時(shí)創(chuàng)建快照,并且在持久化聚合根時(shí)對(duì)比(diff)快照,獲取差異信息,只執(zhí)行需要更新的差異信息。

本篇分享的是筆者實(shí)現(xiàn)的一種方案,雖然每個(gè)團(tuán)隊(duì)定義的DDD代碼規(guī)范不同,但資源庫(kù)的實(shí)現(xiàn)上差異也并不大,因此也具有參考價(jià)值。

首先,抽象聚合根快照存儲(chǔ)器AggregateRootSnapshot,提供緩存聚合根快照、根據(jù)聚合根ID獲取快照、移除快照的方法。

提示:我們約定聚合根必須繼承一個(gè)抽象類BaseAggregate,該抽象類定義獲取聚合根ID的方法,在緩存快照時(shí)可以用聚合根id作為key緩存,這樣在拿的時(shí)候才能根據(jù)聚合根id拿到。

我們可以使用redis實(shí)現(xiàn)聚合根的緩存,但不建議使用性能低的存儲(chǔ)中間件存儲(chǔ),因?yàn)槟菢硬粌H資源庫(kù)的性能沒(méi)能得到優(yōu)化,反正還更影響性能。當(dāng)然,最好的方式是存儲(chǔ)在內(nèi)存中,雖然犧牲點(diǎn)內(nèi)存,這便是以空間換時(shí)間。

我們使用ThreadLocal存儲(chǔ)聚合根快照,因此編寫的AggregateRootSnapshot實(shí)現(xiàn)類如下。

如果聚合根id不是依賴數(shù)據(jù)庫(kù)生成的(我們也不推薦聚合根id依賴數(shù)據(jù)庫(kù)生成,原因在之前的文章已經(jīng)介紹過(guò)了)。為了避免在聚合根為新創(chuàng)建的情況下獲取到錯(cuò)誤的快照,如線程在執(zhí)行上一次業(yè)務(wù)用例(一次接口請(qǐng)求)時(shí),只調(diào)用獲取聚合根的方法,之后沒(méi)有調(diào)用聚合根的存儲(chǔ)方法移除快照(如獲取聚合根詳情),而這次是創(chuàng)建新的聚合根,當(dāng)然也沒(méi)有調(diào)用一次資源庫(kù)獲取聚合根的方法更新快照,那么這次獲取的就將是前一次的快照,因此我們還需要對(duì)比聚合根id是否相同。

只對(duì)比聚合根id當(dāng)然不能確保獲取的就是新的聚合根,能確保聚合根唯一還有這個(gè)條件:“基于每個(gè)業(yè)務(wù)用例都需要先通過(guò)資源庫(kù)獲取到聚合根,最后也需要通過(guò)資源庫(kù)持久化聚合根的特性”,這句話才是最重要的。

提示:ThreadLocal類型字段非靜態(tài),不會(huì)導(dǎo)致內(nèi)存泄露嗎?答案是不會(huì),后面會(huì)講到。

接著,我們?yōu)槭褂藐P(guān)系型數(shù)據(jù)庫(kù)存儲(chǔ)聚合根的資源庫(kù)寫一個(gè)抽象類,需要使用快照優(yōu)化性能的資源庫(kù)可繼承此抽象類。

RepositorySnapshotSupper實(shí)現(xiàn)Repositor接口的findById、save、deleteById方法,另外提供抽象方法由子類實(shí)現(xiàn)。因?yàn)槲覀冃枰趂indById獲取到聚合根時(shí)創(chuàng)建一份聚合根快照并緩存,在真正save聚合根之前獲取快照完成diff判斷,然后將diff結(jié)果交給子類,這樣子類在實(shí)現(xiàn)save時(shí)就可以根據(jù)diff結(jié)果減少不必要的sql。

提示:RepositorySnapshotSupper的快照存儲(chǔ)器并非靜態(tài)的,而快照存儲(chǔ)器的ThreadLocal類型字段也非靜態(tài),因此我們需要確保一個(gè)資源庫(kù)只存在一個(gè)實(shí)例(單例),才不會(huì)導(dǎo)致ThreadLocal內(nèi)存泄露,只是每個(gè)聚合根強(qiáng)引用一個(gè)ThreadLocal。

以上幾步都不是難點(diǎn),難點(diǎn)在于如何實(shí)現(xiàn)快照的創(chuàng)建,以及diff實(shí)現(xiàn)。

快照工具類(SnnapshotUtils)實(shí)現(xiàn)思路:

提前條件:要求實(shí)體與聚合根提供一個(gè)私有的無(wú)參構(gòu)造函數(shù),用于通過(guò)反射創(chuàng)建實(shí)例。

1.通過(guò)反射實(shí)現(xiàn)字段值拷貝,當(dāng)聚合根的字段類型為非實(shí)體類型,那么就是值對(duì)象類型,對(duì)于值對(duì)象類型我們只需要拷貝引用即可;

2.如果是實(shí)體類型集合,則創(chuàng)建一個(gè)新的集合,并將原集合中每個(gè)實(shí)體元素都拷貝一份添加到新集合,將新集合賦給快照,實(shí)體的拷貝規(guī)則同聚合根,可使用遞歸實(shí)現(xiàn)。

Diff工具類實(shí)現(xiàn)思路:

先定義diff結(jié)果類型:未修改、新增、更新、刪除。 圖片

1.對(duì)于聚合根,如果不存在快照即認(rèn)為Insert類型,聚合根下的實(shí)體也全部為Insert類型;

2.對(duì)于聚合根,如果存在快照,那么除實(shí)體類型或?qū)嶓w類型集合字段外,只要其它的任意一個(gè)值對(duì)象不同,就認(rèn)為聚合根diff結(jié)果為Update類型,否則為Non類型;

3.只要聚合根不是新增,不管聚合根有沒(méi)有更新,都不會(huì)影響聚合根下的實(shí)體的diff;

4.如果實(shí)體與聚合根一對(duì)一,即不是集合類型字段,那么:如果對(duì)應(yīng)實(shí)體快照不存在,則認(rèn)diff結(jié)果為Insert,否則如果實(shí)體快照存在但新的為null則認(rèn)為是Delete,否則對(duì)比實(shí)體的各個(gè)值對(duì)象,未修改則為Non,修改則為Update;

5.如果實(shí)體與聚合根是多對(duì)一,即實(shí)體集合,如訂單有多個(gè)訂單item,那么需要一個(gè)個(gè)對(duì)比:新的item在快照中找不到,則為Insert,快照中的item已經(jīng)不存在新的實(shí)體集合,則為Delete,否則對(duì)比item,未修改則為Non,修改則為Update。

定義存儲(chǔ)diff結(jié)果的類:

由于BaseAggregate聚合根實(shí)現(xiàn)了實(shí)體接口(聚合根也是實(shí)體),因此我們?cè)贓ntityDiff中使用Entity引用聚合根/實(shí)體,方便后續(xù)直接從diff中獲取entity執(zhí)行插入、更新,或是獲取entitySnapshot執(zhí)行刪除。(對(duì)于實(shí)體集合,也可存實(shí)體在集合中的索引。)

如果聚合根下的實(shí)體字段是集合類型,那么diff結(jié)果也使用集合存儲(chǔ):

diff工具類的實(shí)現(xiàn):

由于項(xiàng)目代碼不便貼出來(lái),在此我簡(jiǎn)單寫了一個(gè)測(cè)試用例,分享下成果。

訂單聚合根:

提示:使用lombok有個(gè)坑,如果使用@Builder注解,需要提供一個(gè)無(wú)參構(gòu)建方法(建議是私有的構(gòu)建方法),然后在構(gòu)建方法上添加@Tolerate注解。

訂單item實(shí)體:

訂單資源庫(kù)實(shí)現(xiàn):

  • 當(dāng)聚合根的diff結(jié)果類型為Insert時(shí),全量存儲(chǔ)聚合根、聚合根下的實(shí)體;
  • 當(dāng)聚合根的diff結(jié)果類型為Non時(shí),不需要更新聚合根,但聚合根下的實(shí)體是否需要更新還需要根據(jù)聚合根實(shí)體的diff結(jié)果確定;
  • 當(dāng)聚合根的diff結(jié)果類型為Update時(shí),需要更新聚合根;
  • 獲取實(shí)體的diff結(jié)果,根據(jù)diff結(jié)果決定是插入、更新、刪除、還是什么也不做。

單元測(cè)試:

單元測(cè)試結(jié)果如下:

總結(jié)

本篇介紹如何通過(guò)快照+diff的方式優(yōu)化資源庫(kù)的性能,之所有能這樣做是因?yàn)槊總€(gè)業(yè)務(wù)用例都需要先通過(guò)資源庫(kù)獲取到聚合根,最后也需要通過(guò)資源庫(kù)持久化聚合根。出于性能考慮,我們決定以空間換時(shí)間,使用ThrealLocal+反射實(shí)現(xiàn)創(chuàng)建和緩存聚合根快照,最后也使用反射完成diff邏輯。當(dāng)然diff類還存在優(yōu)化空間。

本篇介紹的快照是基于聚合根(DO)的,當(dāng)然我們還可以基于(PO)去實(shí)現(xiàn),也會(huì)更簡(jiǎn)單。

注意:本篇圖片中的代碼可能有bug,未更新到優(yōu)化后的代碼,懶得重新截圖,僅供參考!

參考文獻(xiàn):

阿里技術(shù)專家詳解DDD系列 第三講 - Repository模式

本文轉(zhuǎn)載自微信公眾號(hào)「Java藝術(shù)」,可以通過(guò)以下二維碼關(guān)注。轉(zhuǎn)載本文請(qǐng)聯(lián)系Java藝術(shù)公眾號(hào)。

 

責(zé)任編輯:武曉燕 來(lái)源: Java藝術(shù)
相關(guān)推薦

2023-06-12 07:43:05

知識(shí)庫(kù)性能優(yōu)化

2022-08-23 08:00:59

磁盤性能網(wǎng)絡(luò)

2022-06-09 08:41:17

Go網(wǎng)絡(luò)庫(kù)Gnet

2022-02-07 11:01:23

ZooKeeper

2022-01-02 08:43:46

Python

2021-10-26 10:40:26

代理模式虛擬

2022-05-17 08:02:55

GoTryLock模式

2021-12-04 22:05:02

Linux

2022-03-02 11:37:57

參數(shù)性能調(diào)優(yōu)

2022-06-30 22:53:18

數(shù)據(jù)結(jié)構(gòu)算法

2021-08-01 07:19:16

語(yǔ)言OpenrestyNginx

2021-09-28 08:59:30

復(fù)原IP地址

2021-10-14 10:22:19

逃逸JVM性能

2022-04-12 08:30:52

回調(diào)函數(shù)代碼調(diào)試

2021-10-27 09:59:35

存儲(chǔ)

2021-07-16 22:43:10

Go并發(fā)Golang

2023-03-13 21:38:08

TCP數(shù)據(jù)IP地址

2023-11-01 09:07:01

Spring裝配源碼

2022-10-20 07:39:26

2021-04-29 10:18:18

循環(huán)依賴數(shù)組
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)

主站蜘蛛池模板: 狠狠的干狠狠的操 | 国产精品久久久免费 | 欧美日韩国产一区二区三区 | 国产精品久久久久久久一区探花 | 日日干夜夜操 | 黄色在线免费观看 | 国产精品国产精品国产专区不片 | 日韩精品在线看 | 91精品国产综合久久久久 | 一区二区av| 欧美精品在欧美一区二区少妇 | 狠狠的日 | 国产成人综合一区二区三区 | 中文字幕在线不卡 | 日韩视频一区在线观看 | 国产精品国产三级国产aⅴ无密码 | 日本激情视频在线播放 | 国产精品久久久久久婷婷天堂 | 999观看免费高清www | av一级久久| 国产午夜精品一区二区 | 91精品国产91久久久久久密臀 | 有码一区| 天堂一区二区三区四区 | 成人免费一区二区 | 99re在线视频 | 国产精品久久久久久久久免费丝袜 | 男女啪啪高潮无遮挡免费动态 | 黄网站涩免费蜜桃网站 | 欧美在线a | 一区二区精品 | 欧美高清性xxxxhd | 精品福利一区 | 欧美综合久久 | 毛片免费在线观看 | 操操网站 | 欧洲免费视频 | 国产一级电影网 | 国产精品无码专区在线观看 | 亚洲精品美女在线观看 | 免费精品一区 |