今天主要跟大家分享一下什么是 CQRS,以及在項目中如何去使用。
CRUD系統
我們平常最熟悉的就是三層架構,通常都是通過數據訪問層來修改或者查詢數據,一般修改和查詢使用的是相同的實體。然后通過業務層來處理業務邏輯,將處理結果封裝成DTO對象返回給控制層,再通過前端渲染。反之亦然。
這里基本上是圍繞關系數據庫構建而成的“創建、讀取、更新、刪除”系統(即CRUD系統),此類系統在一些業務邏輯簡單的項目中可能沒有什么問題,但是隨著系統邏輯變得復雜,用戶增多,這種設計就會出現一些性能問題。
我們經常用到的解決方案就是對數據庫進行讀寫分離。讓主數據庫處理事務性的增、刪、改操作,讓從數據庫處理查詢操作,然后主從數據庫之間進行同步。但是這只是從DB角度處理了讀寫分離,從業務或者系統層面上來說,讀和寫的邏輯仍然是存放在一起的,他們都是操作同一個實體對象。
這時候,CQRS 就該登場了。
CQRS系統
簡單的說,CQRS(Command Query Responsibility Segration)就是一個系統,從架構上把 CRUD 系統拆分為兩部分:命令(Command)處理和查詢(Query)處理。其中命令處理包括增、刪、改。
然后命令與查詢兩邊可以用不同的架構實現,以實現CQ兩端(即Command Side,簡稱C端;Query Side,簡稱Q端)的分別優化。兩邊所涉及到的實體對象也可以不同,從而繼續演變成下面這樣。
當然了,CQRS 作為一個讀寫分離思想的架構,在數據存儲方面,也沒有做過多的約束。所以 CQRS可以有不同層次的實現。
CQRS 實現方式
CQRS 可以有兩種實現方式。
1)CQ 兩端數據庫共享,只是在上層代碼上分離。這樣做的好處是可以讓我們的代碼讀寫分離,更容易維護,而且不存在 CQ 兩端的數據一致性問題,因為是共享一個數據庫的。這種架構是非常實用的(也就是我上面畫的那種)。
2)CQ 兩端不僅代碼分離,數據庫也分離,然后Q數數據由C端同步過來。同步方式有兩種:同步或異步,如果需要 CQ 兩端的強一致性,則需要用同步;如果能接受 CQ 兩端數據的最終一致性,則可以使用異步。C端可以采用Event Sourcing(簡稱ES)模式,所有C端的最新數據全部用 Domain Event 表達即可;而要查詢顯示用的數據,則從Q端的 ReadDB(關系型數據庫)查詢即可。
CQRS 的簡單實現
說了這么多,該怎么實現呢?我們以上面提到的第一種方式為例:代碼層面實現分離,數據庫共享。這種方式在企業里也非常實用。
首先有幾個概念需要介紹一下,CQRS 模式中,首先需要有 Command,這個 Command 命令會對應一個實體和一個命令的執行類。那整個系統中肯定有很多不同的 Command,那么還需要一個 CommandBus 來做命令的分發處理。
可能大家覺得比較抽象,我來寫幾行示例代碼,一看就明白了。假設有個訂單模塊,我要新增一個訂單信息。那么根據上文的分析,需要有個新增命令以及對應的訂單實體(并不一定和數據庫的訂單實體完全對應)。首先先創建一個命令接口(綁定命令對應的實體),接口內部有個該命令的處理方法。
OK,接下來我們可以創建訂單的新增命令了。
到這里,我們寫好了具體的創建訂單命令的邏輯,那么該命令需要放到 CommandBus 中去執行,所以我們要寫這個 CommandBus。
可能大家會看著有點暈,甚至有點繞,沒關系,我解釋一下:這個 dispatch 方法就相當于分發執行,內部根據傳入的具體 Command 以及對應的 model,去執行該 Command 實現的邏輯。
好了,那我們在熟悉的 Controller 層該如何去調用呢?很簡單,如下:
我還寫了一個獲取訂單信息的接口,大家有沒有發現,查詢和插入是不同的方式,插入走的是 CommandBus 分發到 CreateOrderCommand 去執行,而查詢則是直接走 service 層去查。這就是 CQRS 模式。
當然了,當命令越來越多的時候,也可以將 CommandBus 抽象出接口,可以根據業務需求,實現多個不同的 CommandBus 來分發命令。
除此之外,CQRS 還可以用在任務調度模塊中,不同的任務可以包含不同的 Command,實際中運用是非常廣泛的。
總結
CQRS 是一種思想很簡單清晰的設計模式,他通過在業務上分離操作和查詢來使得系統具有更好的可擴展性及性能,使得能夠對系統的不同部分進行擴展和優化。在 CQRS 中,所有的涉及到對 DB 的操作都是通過發送 Command,然后特定的 Command 觸發對應事件來完成操作,也可以做成異步的,主要看業務上的需求了。
CQRS 雖然在思想上簡單,但是實現上相對來說復雜些,也涉及到 DDD 的一些概念了,當然了,這篇文章主要是介紹以及演示 CQRS 模式的基本實踐,更多知識需要大家再深入的去學習。
責任編輯:韓希宇
免責聲明:
中國電子銀行網發布的專欄、投稿以及征文相關文章,其文字、圖片、視頻均來源于作者投稿或轉載自相關作品方;如涉及未經許可使用作品的問題,請您優先聯系我們(聯系郵箱:cebnet@cfca.com.cn,電話:400-880-9888),我們會第一時間核實,謝謝配合。