溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

DDD里面的CQRS是什么

發(fā)布時(shí)間:2021-10-22 09:35:27 來(lái)源:億速云 閱讀:159 作者:iii 欄目:數(shù)據(jù)庫(kù)

這篇文章主要介紹“DDD里面的CQRS是什么”,在日常操作中,相信很多人在DDD里面的CQRS是什么問(wèn)題上存在疑惑,小編查閱了各式資料,整理出簡(jiǎn)單好用的操作方法,希望對(duì)大家解答”DDD里面的CQRS是什么”的疑惑有所幫助!接下來(lái),請(qǐng)跟著小編一起來(lái)學(xué)習(xí)吧!

開(kāi)篇

隨著業(yè)務(wù)不斷發(fā)展,軟件系統(tǒng)的架構(gòu)也越來(lái)越復(fù)雜,但無(wú)論多復(fù)雜的業(yè)務(wù)最終在系統(tǒng)中實(shí)現(xiàn)的時(shí)候,無(wú)非是讀寫(xiě)操作。用戶根據(jù)業(yè)務(wù)規(guī)則寫(xiě)入商業(yè)數(shù)據(jù),再根據(jù)查詢規(guī)則獲取想要的結(jié)果。通常而言我們會(huì)講這些讀寫(xiě)的數(shù)據(jù)放到一個(gè)數(shù)據(jù)庫(kù)中保存,通過(guò)一套模型對(duì)其進(jìn)行讀寫(xiě)操作。而在大型系統(tǒng)中往往查詢操作遠(yuǎn)遠(yuǎn)多于寫(xiě)入操作,于是就有了讀寫(xiě)分離的思想,將讀操作和寫(xiě)操作的模型分開(kāi)定義并且提供不同的通道供用戶使用。CQRS(Command-Query  Responsibility Segregation) 就是基于這一思想提供的一種模式讀寫(xiě)分離的模式,今天就圍繞著它給大家講述以下內(nèi)容:

  • CQRS的演變和架構(gòu)

  • Event Sourcing 原理與應(yīng)用

  • Event Sourcing 與CQRS的完美結(jié)合

  • CQRS的例子

CQRS的演變和架構(gòu)

CQRS(Command-Query Responsibility Segregation)  是一種讀寫(xiě)分離的模式,從字面意思上理解Command是命令的意思,其代表寫(xiě)入操作;Query是查詢的意思,代表的查詢操作,這種模式的主要思想是將數(shù)據(jù)的寫(xiě)入操作和查詢操作分開(kāi)。

它源于Bertrand  Mayer設(shè)計(jì)的命令查詢分離(CQS)原理。CQS聲明一個(gè)類只能有兩種方法:改變狀態(tài)并返回void的方法和返回狀態(tài)的方法。而Greg Young  是負(fù)責(zé)命名這種模式為CQRS 并推廣它的人。

首先來(lái)看看在沒(méi)有CQRS之前是如何處理系統(tǒng)中的修改和查詢的吧,如圖1所示:

DDD里面的CQRS是什么

圖1 傳統(tǒng)的系統(tǒng)請(qǐng)求

傳統(tǒng)的系統(tǒng)請(qǐng)求從最左邊的Client開(kāi)始,沿著紅線往右通過(guò)Application Service對(duì)系統(tǒng)進(jìn)行請(qǐng)求。這里Application Service  可以理解為系統(tǒng)的門(mén)面,或者是Controller層負(fù)責(zé)接收客戶端的請(qǐng)求,此時(shí)請(qǐng)求的內(nèi)容比較簡(jiǎn)單基本和數(shù)據(jù)庫(kù)中的信息一致,因此這里使用DTO(Data  Transfer Object)直接請(qǐng)求。DTO經(jīng)過(guò)Domain Model  以后直接到達(dá)Database,從而沿著藍(lán)色的線條返回給Client端。傳統(tǒng)的請(qǐng)求方式部分讀操作和寫(xiě)操作,都使用同樣的數(shù)據(jù)模型和一套Domain  Model以及相同的數(shù)據(jù)庫(kù)。

從傳統(tǒng)操作來(lái)看Client的請(qǐng)求在經(jīng)過(guò)Application Service,用戶意圖全部被分解為CRUD操作,但是在Domain  Model中是無(wú)法體現(xiàn)的。為保證DTO的完整性和一致性,與操作無(wú)關(guān)的信息會(huì)被納入DTO,查詢操作和創(chuàng)建操作都共用一個(gè)DTO,而領(lǐng)域模型的業(yè)務(wù)流程被弱化。為了適應(yīng)同時(shí)適應(yīng)查詢和創(chuàng)建操作,DTO被設(shè)計(jì)的面面俱到,也就顯得臃腫。從而在傳輸中存在不必要的字段傳遞。

而且一次操作,在DTO與領(lǐng)域?qū)ο箝g進(jìn)行多次轉(zhuǎn)換,增加了系統(tǒng)復(fù)雜度。還有,讀寫(xiě)操作將圍繞同一數(shù)據(jù)模型展開(kāi),對(duì)于讀多寫(xiě)少的系統(tǒng)而言效率并不是最高的,特別在讀操作為主的高并發(fā)系統(tǒng)中缺點(diǎn)就尤為突出。

正因?yàn)閭鹘y(tǒng)系統(tǒng)架構(gòu)存在上面這些問(wèn)題,因此CQRS根據(jù)讀寫(xiě)職責(zé)的不同,把領(lǐng)域模型切分為Command端與Query端兩個(gè)部分,如圖2所示,紅色線部分就是Command端,其對(duì)應(yīng)的是Domain  Model 對(duì)其發(fā)送Command 操作的指令往數(shù)據(jù)寫(xiě)入狀態(tài)信息。

Query端作為查詢操作,由藍(lán)色的線表示,通過(guò)Query  Model向數(shù)據(jù)庫(kù)獲取信息,通過(guò)黑色向左的先返回結(jié)果給Client。Command端與Query端都通過(guò)Application Service  進(jìn)入系統(tǒng),共享同一個(gè)數(shù)據(jù)庫(kù),但Command端只寫(xiě)入狀態(tài),Query端只讀取狀態(tài)。

DDD里面的CQRS是什么

圖2 CQRS 分為Command 端和 Query端

目前而言已經(jīng)將讀寫(xiě)操作分開(kāi)了,由于兩個(gè)操作依舊共用一個(gè)數(shù)據(jù)庫(kù),為了提高讀寫(xiě)效率數(shù)據(jù)庫(kù)的分離就成為必然的選擇。如圖3所示,于是將原來(lái)的Database,分離為Writer  Database 和Reader Database分別用于寫(xiě)操作和讀操作。為了保證讀寫(xiě)操作的數(shù)據(jù)一致性,需要在兩個(gè)數(shù)據(jù)庫(kù)之間進(jìn)行數(shù)據(jù)同步。

由于數(shù)據(jù)同步是由時(shí)效性的,因此寫(xiě)入方是Command端,讀取方是Query端,因此系統(tǒng)智能保證最終一致性。那么如何保證兩個(gè)庫(kù)之間的同步呢?下面需要引入Event  Sourcing的概念。

Event Sourcing 原理與應(yīng)用

Event Sourcing也叫事件溯源,是Martin  Fowler提出的一種架構(gòu)模式。其設(shè)計(jì)思想是系統(tǒng)中的業(yè)務(wù)都由事件驅(qū)動(dòng)來(lái)完成。系統(tǒng)中記錄的是一個(gè)個(gè)事件,由這些事件體現(xiàn)信息的狀態(tài)。業(yè)務(wù)數(shù)據(jù)可以是事件產(chǎn)生的視圖,不一定要保存到數(shù)據(jù)庫(kù)中。

為了便于理解Event Sourcing 我們通過(guò)一個(gè)例子來(lái)進(jìn)一步解釋,如圖3 所示:

DDD里面的CQRS是什么

圖3 Command 端和 Query端 讀寫(xiě)數(shù)據(jù)庫(kù)的分離

我們從左往右看。對(duì)于一個(gè)業(yè)務(wù)類“賬戶”,擁有“屬性”包括“賬戶ID”和“賬戶金額”信息,同時(shí)擁有“方法”包括“創(chuàng)建賬戶”、“存現(xiàn)金”和“取現(xiàn)金”。中間綠色的事件序列,是針對(duì)“賬戶”進(jìn)行的一些列操作,按照其中的序列號(hào)來(lái)看。

1. 創(chuàng)建了一個(gè)銀行賬戶,假設(shè)此時(shí)的賬戶ID為“0001”。

2. 針對(duì)“0001”這個(gè)賬戶存入300元現(xiàn)金。

3. 然后從“0001”這個(gè)賬戶取出100元現(xiàn)金。

4. 最后,再存入200元。

上面生成的這一系列事件會(huì)保存到下方的Event  Store的事件庫(kù)中,這里并不會(huì)保存“賬戶”的狀態(tài)信息。當(dāng)需要獲取“賬戶”數(shù)據(jù)的時(shí)候,會(huì)通過(guò)這些事件信息,還原成“賬戶”的最終狀態(tài),也就是“賬戶ID”為“0001”,“賬戶金額”為400。其具體實(shí)現(xiàn)方式是,通過(guò)賬戶相關(guān)的四個(gè)事件對(duì)應(yīng)的處理方法,重新生成當(dāng)前狀態(tài)。如果每次查詢狀態(tài)信息都需要這樣處理勢(shì)必會(huì)造成資源的浪費(fèi),因此在右側(cè)黃色的部分,我們將最終的“賬戶”信息通過(guò)視圖的方式保存下來(lái),以供查詢。

DDD里面的CQRS是什么

圖3 Event Sourcing 實(shí)例圖

上面這個(gè)“賬戶”處理的過(guò)程,就是Event  Sourcing,說(shuō)白了就是通過(guò)事件的處理模式。它將系統(tǒng)中的操作都按照事件的方式記錄并保存,任何實(shí)體的最終狀態(tài)都是通過(guò)事件的疊加和還原確認(rèn)的。

Event Sourcing 包含的內(nèi)容

上面介紹了Event Sourcing 的執(zhí)行原理和基本概念,這里一起來(lái)看看其包含的主要內(nèi)容,便于我們對(duì)它有更加全面的理解。

聚合對(duì)象:圖3的例子中“賬戶”就是一個(gè)聚合對(duì)象,它里面包含“賬戶ID”、“賬戶金額”等的基本信息,也包含了對(duì)賬戶操作的方法:“創(chuàng)建賬戶”、“存現(xiàn)金”、“取現(xiàn)金”。同時(shí)“賬戶”在領(lǐng)域驅(qū)動(dòng)開(kāi)發(fā)中對(duì)應(yīng)的是一個(gè)領(lǐng)域模型。

  • Event Store:在Event Sourcing模式中,事件所保存的數(shù)據(jù)庫(kù)稱為Event  Store。在事件中需要包含聚合對(duì)象的ID,以及事件的順序。這樣在查詢的時(shí)候可以根據(jù)聚合ID從數(shù)據(jù)庫(kù)中找到相關(guān)的事件,并通過(guò)事件的序號(hào)還原執(zhí)行順序。也就是事件的重現(xiàn),也就是某一時(shí)刻執(zhí)行的事件取出來(lái),調(diào)用他的處理函數(shù),還原那個(gè)時(shí)間點(diǎn)的業(yè)務(wù)狀態(tài)。

  • 為了獲取最新的“賬戶”狀態(tài)信息,需要通過(guò)Event Sourcing  中獲取對(duì)應(yīng)的事件進(jìn)行回放,從而獲取當(dāng)前的狀態(tài),這樣的操作會(huì)浪費(fèi)很多資源。因此我們會(huì)將聚合對(duì)象的最新數(shù)據(jù)狀態(tài),寫(xiě)到一個(gè)表中,這個(gè)表就是視圖。又或者將這個(gè)狀態(tài)信息發(fā)送給其他的應(yīng)用程序進(jìn)行后續(xù)的業(yè)務(wù)操作。

  • 查詢的內(nèi)容是針對(duì)“賬戶”最終狀態(tài)的,因此針對(duì)的對(duì)象應(yīng)該是視圖。這里的設(shè)定剛好的CQRS中的讀寫(xiě)分離不謀而合,通過(guò)Event Store存放Command  端的Event 信息,通過(guò)視圖存放實(shí)體最終狀態(tài)的信息,而Query 端從視圖查詢數(shù)據(jù)返回給用戶。

Event Sourcing 的優(yōu)缺點(diǎn)

上面介紹了Event Sourcing的原理和內(nèi)容以后再來(lái)看看它的優(yōu)缺點(diǎn)。

Event Sourcing 的優(yōu)點(diǎn):

  • 溯源事件與重現(xiàn)操作:特別是在業(yè)務(wù)復(fù)雜的系統(tǒng)中,一個(gè)事務(wù)包含多個(gè)操作,它們有的是并行有的串行,如果需要了解操作的執(zhí)行就需要對(duì)每個(gè)事件了如指掌。Event  Sourcing 恰恰提供了事件的歷史信息,方便查找任何時(shí)間點(diǎn)發(fā)生的事情。

  • 追蹤和修復(fù)Bug:可以通過(guò)事件分析業(yè)務(wù)的執(zhí)行過(guò)程,幫助發(fā)現(xiàn)Bug,例如重方Bug產(chǎn)生時(shí)的事件序列,從而定位Bug所處位置。發(fā)現(xiàn)Bug并且修復(fù)以后,可以通過(guò)重新聚合業(yè)務(wù)數(shù)據(jù),重放執(zhí)行的事件序列驗(yàn)證修復(fù)結(jié)果,同時(shí)將Bug造成的損失進(jìn)行挽回。

  • 提高性能:Event  Sourcing模式下,由于是記錄事件執(zhí)行的序列,因此都是新增操作,沒(méi)有更新操作,相對(duì)于需要更新操作的系統(tǒng)而言記錄數(shù)據(jù)的性能是提高了。如果使用視圖的方式將實(shí)體的最終狀態(tài)可以傳遞給其他的應(yīng)用,而不用寫(xiě)入數(shù)據(jù)庫(kù)以后再讀取,這種做法也提高了效率。

Event Sourcing 的缺點(diǎn):

  • 轉(zhuǎn)變思路:Event  Sourcing的落地需要在設(shè)計(jì)時(shí)就用領(lǐng)域驅(qū)動(dòng)的方式開(kāi)展,需要有基于事件的響應(yīng)式編程思維。這種方式需要以領(lǐng)域模型設(shè)計(jì)優(yōu)先,而不是傳統(tǒng)的數(shù)據(jù)庫(kù)設(shè)計(jì)優(yōu)先。

  • 變更事件結(jié)構(gòu):隨著業(yè)務(wù)流程的變化需要不斷調(diào)整事件結(jié)構(gòu),對(duì)事件添加或者修改一些數(shù)據(jù)。這種行為會(huì)影響到“歷史重現(xiàn)”,需要考慮兼容之前的事件結(jié)構(gòu)。

  • 處理冪等事件:如果對(duì)應(yīng)的事務(wù)在執(zhí)行過(guò)程中被中斷,需要通過(guò)事件回放的方式達(dá)到事務(wù)的最終一致性問(wèn)題。此時(shí)需要對(duì)事件的冪等性提出要求,也就是同一個(gè)事件運(yùn)行多次得到的結(jié)果不變。需要在事件處理時(shí)丟棄重復(fù)事件。

  • 查詢事件數(shù)據(jù)庫(kù)(event  store):由于數(shù)據(jù)庫(kù)中存放的一個(gè)個(gè)事件,如果針對(duì)實(shí)體狀態(tài)的查詢會(huì)相對(duì)困難。需要將這些事件重放,獲取最新的實(shí)體狀態(tài)的信息。這也是為什么需要通過(guò)CQRS的方式將讀寫(xiě)進(jìn)行分離,Command端使用Event  Sourcing 而Query端使用Event Sourcing 發(fā)出Event 的最終狀態(tài)進(jìn)行查詢的原因。

CQRS與Event Sourcing的 完美結(jié)合

通過(guò)上面對(duì)Event Sourcing 的介紹,可以發(fā)現(xiàn)它針對(duì)Event 進(jìn)行記錄存放到Event  Store中,并且把最終的狀態(tài)放到視圖中進(jìn)行保存可以供給Query端進(jìn)行查詢。這種模式天生與CQRS就有默契的配合。

從CQRS模式的結(jié)構(gòu)看,實(shí)體狀態(tài)的變化發(fā)生在Command端,Command端知道業(yè)務(wù)處理進(jìn)行了哪些具體操作,將這些具體的操作進(jìn)行封裝就形成了Event。

而Query端,查詢返回的是實(shí)體當(dāng)前狀態(tài)狀態(tài)。根據(jù)“當(dāng)前狀態(tài) + 變化 =  新的狀態(tài)”,如果能從Command端得到“變化”,再加上Query端自身獲取的“當(dāng)前狀態(tài)”就能得到變化后的“新的狀態(tài)”。

此時(shí)Command  端發(fā)出的Event正好符合這個(gè)“變化”,如果當(dāng)變化發(fā)生也就是新Event產(chǎn)生時(shí),由Command端將這個(gè)Event推送到Query端,Query端根據(jù)Event刷新?tīng)顟B(tài),就能保證兩端實(shí)體狀態(tài)一致,達(dá)到最終一致性,如圖4所示:

DDD里面的CQRS是什么

圖4 Event Sourcing 和 CQRS 結(jié)合

在圖3的基礎(chǔ)上加入Event Handler 也就是圖中藍(lán)色部分,這部分接收從Domain  Model中發(fā)過(guò)來(lái)的Event信息,也就是最新的實(shí)體修改信息。再將這個(gè)信息存放到Reader Database(也可以理解為視圖)中,這樣新的Event  信息加上當(dāng)前的實(shí)體信息就時(shí)最新的實(shí)體信息了。而采用這種方式以后Query 端依舊可以通過(guò)Reader  Database獲取數(shù)據(jù)對(duì)其原來(lái)的操作并沒(méi)有產(chǎn)生影響。

再回到Command端,其對(duì)應(yīng)的多次操作的Event 會(huì)存放到Event Store中,作為業(yè)務(wù)跟蹤的記錄被保存下來(lái)。

上面提到的只是一種系統(tǒng)架構(gòu)的模式,在實(shí)際運(yùn)用中可以根據(jù)具體情況進(jìn)行改進(jìn)和優(yōu)化。如圖5所示,可以在Command 端和Query 端進(jìn)行Event  交換的時(shí)候加入隊(duì)列,滿足兩套應(yīng)用程序部署在不同進(jìn)程的場(chǎng)景需求。

DDD里面的CQRS是什么

圖5 Command 端和Query 端加入隊(duì)列

一個(gè)CQRS的例子

上面聊到了CQRS與Event Sourcing的完美結(jié)合,這里通過(guò)一個(gè)例子給大家進(jìn)一步介紹其運(yùn)作的過(guò)程。這個(gè)例子的背景是,對(duì)于用戶(User)  而言保存了對(duì)應(yīng)的聯(lián)系方式(Contact)和住址(Address)。

Command 用來(lái)建立(Create)用戶( User) 和更新(Update)用戶(User);Query  用來(lái)查詢用戶(User)對(duì)應(yīng)的住址(Address)和聯(lián)系方式(Contact)。

如圖4所示,Client 請(qǐng)求應(yīng)用分為上線兩條線,分別用四種顏色代表。我們根據(jù)不同顏色來(lái)講解Command 端和Query 端執(zhí)行的過(guò)程。

DDD里面的CQRS是什么

圖4 Event Sourcing 和 CQRS 結(jié)合

紅色向左的線:這里主要是針對(duì)User 的create 和update  操作,分別填充CreateUserCommand類和UpdateUserCommand類,作為UserAggregate聚合類的輸入?yún)?shù)。在UserAggregate中分別由,handleCreateUserCommand和handleUpdateUserCommand兩個(gè)方法處理,最后通過(guò)UserWriteRepository來(lái)保存到Write  database中。

  • 綠色向下的線:其連接了紫色的區(qū)域是UserProjection,它的作用是將Write database的數(shù)據(jù)同步到Read database中。

  • 藍(lán)色向右的線:Client  發(fā)起Query請(qǐng)求通過(guò)AddressByRegionQuery類和ContactByTypeQuery類構(gòu)建請(qǐng)求,將其傳送到UserProjection類進(jìn)行處理,其中handle方法分別對(duì)兩類參數(shù)的請(qǐng)求進(jìn)行處理。最后通過(guò)UserReadRepository獲取Read  database中的信息。

  • 紫色向左的線:當(dāng)從Read database 中獲取信息以后,返回給Client。

DDD里面的CQRS是什么

圖6 CQRS 例子圖解

在了解了整體架構(gòu)以后再來(lái)看看具體實(shí)現(xiàn)的類結(jié)構(gòu)。

如圖7 所示,User實(shí)體類包括如下幾個(gè)字段,也就是我們要操作的業(yè)務(wù)實(shí)體。包括用戶的基本信息,其中contact 和address  類的具體信息在這里不展開(kāi)描述。

DDD里面的CQRS是什么

圖7 User 實(shí)體類

Command  的類信息如圖8所示,其內(nèi)容相對(duì)簡(jiǎn)單。針對(duì)CreateUserCommand主要用于創(chuàng)建用戶,包括UserID和FirstName以及LastName。

DDD里面的CQRS是什么

圖8 CreateUserCommand 類

如圖9所示,UpdateUserCommand中加入了地址和聯(lián)系方式的更新內(nèi)容。

DDD里面的CQRS是什么

圖9 UpdateUserCommand 類

有了Command  再來(lái)看看聚合類UserAggregate,由于其中包括Create和Update的處理方法,這里介紹其中的handleCreateUserCommand方法,也就是處理新建用戶命令。

這里會(huì)創(chuàng)建一個(gè)UserCreatedEvent對(duì)象,并將其通過(guò)WriteRepository保存到Write  database中。也就是在ES中的Event store,同時(shí)會(huì)將event 的list返回。

DDD里面的CQRS是什么

圖10 handleCreateUserCommand 類

在處理完Command  以后會(huì)返回Event,這個(gè)Event在保存到數(shù)據(jù)庫(kù)中的同時(shí),也會(huì)發(fā)送和Query端作為最新的實(shí)體狀態(tài)進(jìn)行更新,這里會(huì)用到UserProjector類完成映射。如圖11,所示,其中的project方法會(huì)針對(duì)UserID的events進(jìn)行逐一處理。

DDD里面的CQRS是什么

圖11 UserProjector 類

看完了Command 端和 同步的Projector,再來(lái)看看Query端的類。如圖12  所示,AddressByRegionQuery類定義了UserID和State信息。

DDD里面的CQRS是什么

圖12 AddressByRegionQuery 類

如圖13 所示,ContactByTypeQuery定義了UserID和ContactType的信息。

DDD里面的CQRS是什么

圖13 ContactByTypeQuery 類

如圖14所示,上面提到的AddressByRegionQuery和ContactByTypeQuery作為參數(shù)傳入到UserProjection類的handle方法中,并且返回對(duì)應(yīng)的Contact和Address信息。使用了UserReadRepositiory從Read  database中獲取數(shù)據(jù)。

DDD里面的CQRS是什么

圖14 UserProjection

最后,再來(lái)看看測(cè)試代碼這里將其分為7個(gè)步驟,如圖15所示。

隨機(jī)生成用戶ID。

  1. 鴻蒙官方戰(zhàn)略合作共建——HarmonyOS技術(shù)社區(qū)

  2. 通過(guò)CreateUserCommand,創(chuàng)建新建用戶的Command,并且通過(guò)UserAggregate生成對(duì)應(yīng)的事件。

  3. 通過(guò)UserProjector將事件映射到Query端的數(shù)據(jù)庫(kù)中。

  4. 通過(guò)UpdateUserCommand,創(chuàng)建更新地址信息的Command,生成對(duì)應(yīng)的事件。

  5. 通過(guò)UserProjector將事件映射到Query端的數(shù)據(jù)庫(kù)中。

  6. 通過(guò)AddressByRegionQuery,創(chuàng)建查詢地址信息的Query。

  7. 執(zhí)行查詢從Read database 中獲取數(shù)據(jù)與假設(shè)值進(jìn)行比較。

DDD里面的CQRS是什么

圖15 Command 和Query的執(zhí)行過(guò)程

最后來(lái)看看這些文件的目錄結(jié)構(gòu),如圖16所示。

DDD里面的CQRS是什么

圖16 文件結(jié)構(gòu)

到此,關(guān)于“DDD里面的CQRS是什么”的學(xué)習(xí)就結(jié)束了,希望能夠解決大家的疑惑。理論與實(shí)踐的搭配能更好的幫助大家學(xué)習(xí),快去試試吧!若想繼續(xù)學(xué)習(xí)更多相關(guān)知識(shí),請(qǐng)繼續(xù)關(guān)注億速云網(wǎng)站,小編會(huì)繼續(xù)努力為大家?guī)?lái)更多實(shí)用的文章!

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI