1. 什么是CQRS
CQRS最早來自於Betrand Meyer(Eiffel語言之父,開-閉原則OCP提出者)在 Object-Oriented Software Construction 這本書中提到的一種 命令查詢分離 (Command Query Separation,CQS) 的概念。其基本思想在於,任何一個對象的方法可以分為兩大類:
|
---|
根據CQS的思想,任何一個方法都可以拆分為命令和查詢兩部分。比如:
private int i = 0; private int Increase(int value) { i += value; return i; }
這個方法,我們執行了一個命令即對變量i進行相加,同時又執行了一個Query,即查詢返回了i的值,如果按照CQS的思想,該方法可以拆成Command和Query兩個方法,如下:
private void increaseCommand(int value) { i += value; } private int queryValue() { return i; }
操作和查詢分離使得我們能夠更好的把握對象的細節,能夠更好的理解哪些操作會改變系統的狀態。當然CQS也有一些缺點,比如代碼需要處理多線程的情況。
CQRS是對CQS模式的進一步改進成的一種簡單模式。 它由Greg Young在CQRS, Task Based UIs, Event Sourcing agh! 這篇文章中提出。“CQRS只是簡單的將之前只需要創建一個對象拆分成了兩個對象,這種分離是基於方法是執行命令還是執行查詢這一原則來定的(這個和CQS的定義一致)”。 |
---|
CQRS使用分離的接口將數據查詢操作(Queries)和數據修改操作(Commands)分離開來,這也意味着在查詢和更新過程中使用的數據模型也是不一樣的。這樣讀和寫邏輯就隔離開來了。
使用CQRS分離了讀寫職責之后,可以對數據進行讀寫分離操作來改進性能,可擴展性和安全。
2. 為什么要引入CQRS
CQRS模式有一些優點:
- 分工明確,可以負責不同的部分
- 將業務上的命令和查詢的職責分離能夠提高系統的性能、可擴展性和安全性。並且在系統的演化中能夠保持高度的靈活性,能夠防止出現CRUD模式中,對查詢或者修改中的某一方進行改動,導致另一方出現問題的情況。
- 邏輯清晰,能夠看到系統中的那些行為或者操作導致了系統的狀態變化。
- 可以從數據驅動(Data-Driven) 轉到任務驅動(Task-Driven)以及事件驅動(Event-Driven).
在下場景中,可以考慮使用CQRS模式:
- 當在業務邏輯層有很多操作需要相同的實體或者對象進行操作的時候。CQRS使得我們可以對讀和寫定義不同的實體和方法,從而可以減少或者避免對某一方面的更改造成沖突
- 對於一些基於任務的用戶交互系統,通常這類系統會引導用戶通過一系列復雜的步驟和操作,通常會需要一些復雜的領域模型,並且整個團隊已經熟悉領域驅動設計技術。寫模型有很多和業務邏輯相關的命令操作的堆,輸入驗證,業務邏輯驗證來保證數據的一致性。讀模型沒有業務邏輯以及驗證堆,僅僅是返回DTO對象為視圖模型提供數據。讀模型最終和寫模型相一致。
- 適用於一些需要對查詢性能和寫入性能分開進行優化的系統,尤其是讀/寫比非常高的系統,橫向擴展是必須的。比如,在很多系統中讀操作的請求時遠大於寫操作。為適應這種場景,可以考慮將寫模型抽離出來單獨擴展,而將寫模型運行在一個或者少數幾個實例上。少量的寫模型實例能夠減少合並沖突發生的情況
- 適用於一些團隊中,一些有經驗的開發者可以關注復雜的領域模型,這些用到寫操作,而另一些經驗較少的開發者可以關注用戶界面上的讀模型。
- 對於系統在將來會隨着時間不段演化,有可能會包含不同版本的模型,或者業務規則經常變化的系統
- 需要和其他系統整合,特別是需要和事件溯源Event Sourcing進行整合的系統,這樣子系統的臨時異常不會影響整個系統的其他部分。
3. 系統如何實現
CQRS采用Spring MVC+Scala+Scala sql是實現。
1) Spring MVC及封裝的Spring Boot作為一個Javaer這里就不再贅述。
2) 為什么要用Scala語言開發:
首先,Scala也是基於JVM的語言,可以直接調用Java API及強大三方庫; |
---|
3) 為什么用Scala sql代替MyBatis:
Scala-sql (原作者請參考)是一個輕量級的 JDBC 庫,提供了在scala中訪問關系型數據庫的一個簡單的API,其定位是對面 scala開發者,提供一個可以替換 spring-jdbc, MyBatis 的數據訪問庫。相比 spring-jdbc, MyBatis, Hibernate 等庫,scala-sql有一些自己獨特的特點: |
---|
4) 代碼結構
Demo源碼請參考: