一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

服務(wù)器之家:專注于服務(wù)器技術(shù)及軟件下載分享
分類導(dǎo)航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術(shù)|正則表達(dá)式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務(wù)器之家 - 編程語言 - Java教程 - 使用Spring Data JDBC實現(xiàn)DDD聚合的示例代碼

使用Spring Data JDBC實現(xiàn)DDD聚合的示例代碼

2021-06-02 14:14解道 Java教程

這篇文章主要介紹了使用Spring Data JDBC實現(xiàn)DDD聚合的示例代碼,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧

本文討論了spring data jdbc如何實現(xiàn)ddd中聚合根存儲的設(shè)計思路,其中主要討論了是不是每個實體都需要一個對應(yīng)數(shù)據(jù)表,這種問題需要根據(jù)具體情況而定。

spring data jdbc比jpa更容易理解,比如對象引用特性會很有趣。作為第一個示例,請考慮以下領(lǐng)域模型:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class purchaseorder {
 
 private @id long id;
 private string shippingaddress;
 private set<orderitem> items = new hashset<>();
 
 void additem(int quantity, string product) {
  items.add(createorderitem(quantity, product));
 }
 
 private orderitem createorderitem(int quantity, string product) {
 
  orderitem item = new orderitem();
  item.product = product;
  item.quantity = quantity;
  return item;
 }
}
class orderitem {
 int quantity;
 string product;
}

另外,考慮如下定義的存儲庫:

?
1
2
3
4
5
interface orderrepository extends crudrepository<purchaseorder, long> {
 
 @query("select count(*) from order_item")
 int countitems();
}

如果使用商品創(chuàng)建訂單,希望所有商品都能保存:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
@autowired orderrepository repository;
 
@test
public void createupdatedeleteorder() {
 
 purchaseorder order = new purchaseorder();
 order.additem(4, "captain future comet lego set");
 order.additem(2, "cute blue angler fish plush toy");
 
 purchaseorder saved = repository.save(order);
 
 assertthat(repository.count()).isequalto(1);
 assertthat(repository.countitems()).isequalto(2);
 

此外,如果刪除purchaseorder,它的所有項目也應(yīng)該被刪除。

?
1
2
3
4
5
6
 repository.delete(saved);
 
 assertthat(repository.count()).isequalto(0);
 assertthat(repository.countitems()).isequalto(0);
}

如果我們需要一個語法上相同但語義上不同的關(guān)系呢?上述訂單中包含訂單條目orderitem , 當(dāng)訂單刪除時,包含的orderitem 都刪除了,但是看看看看下面案例,也是使用包含一個集合:

?
1
2
3
4
class book {
 // …
 set<author> authors = new hashset<>();
}

當(dāng)書籍絕版時,將book刪除。所有的作者author也都丟失了。這當(dāng)然不是你想要的,因為一些作者可能也寫過其他書。

怎么辦?

讓我們看一看存儲庫實際存在的內(nèi)容。這與一遍又一遍的問題密切相關(guān):是否應(yīng)該在jpa中為每個表創(chuàng)建一個存儲庫?

而正確和權(quán)威的答案是“不”。存儲庫持久聚合并加載聚合。聚合是一個包含各種對象的群,它應(yīng)始終保持一致。此外,它應(yīng)始終保持(和加載)在一起。它有一個對象,稱為聚合根,它是唯一允許外部訪問或引用聚合內(nèi)部的代理或管理者。聚合根是傳遞給存儲庫的,以便持久化聚合里面的對象群。

這提出了一個問題:spring data jdbc如何確定什么是聚合的一部分,哪些不是?答案非常簡單:非瞬態(tài)non-transient 引用都是聚合的一部分,這樣就可從聚合根到達(dá)聚合內(nèi)部所有內(nèi)容。

orderitem實例是聚合的一部分,因此被刪除; author正好相反,實例不是book聚合的一部分,因此不應(yīng)刪除。所以不應(yīng)該從book內(nèi)部去引用那些作者author對象。

問題解決了。好吧,......不是真的。我們?nèi)匀恍枰鎯驮L問有關(guān)book和author之間的關(guān)系信息。答案可以在領(lǐng)域驅(qū)動設(shè)計(ddd)中找到,它建議使用id而不是直接引用。這適用于各種多對x關(guān)系。

如果多個聚合引用同一個實體,則該實體不能成為引用它的多個聚合的一部分,因為它只能是其中一個聚合的一部分。因此,任何“多對一”和“多對多”關(guān)系都只能通過引用id來建模實現(xiàn)了。

這樣可以實現(xiàn)多種目的:

1. 清楚地表示了聚合的邊界。

2. 還完全解耦(至少在應(yīng)用程序的領(lǐng)域模型中)所涉及的兩個聚合。

3. 這種分離可以用不同的方式在數(shù)據(jù)庫中表示:

a. 以通常的方式保留數(shù)據(jù)庫,包括所有外鍵。這意味著必須確保以正確的順序創(chuàng)建和保留聚合。

b. 使用延遲約束,僅在事務(wù)的提交階段進(jìn)行檢查。這可能會提高吞吐量。它還編纂了最終一致性的版本,其中“最終”與交易結(jié)束相關(guān)聯(lián)。這也允許引用從未存在的聚合,只要它僅在事務(wù)期間發(fā)生。這對于避免大量基礎(chǔ)結(jié)構(gòu)代碼只是為了滿足外鍵和非空約束可能是有用的。

c. 完全刪除外鍵,實現(xiàn)真正的最終一致性。

d. 將引用的聚合保留在不同的數(shù)據(jù)庫中,甚至可能是no sql存儲。

無論如何,即使spring data jdbc也鼓勵應(yīng)用模塊化。此外,如果嘗試遷移一個具有10年歷史的單體,你就會明白它的價值。

使用spring data jdbc,您可以建模多對多關(guān)系,如下所示:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
class book {
 
 private @id long id;
 private string title;
 private set<authorref> authors = new hashset<>();
 
 public void addauthor(author author) {
  authors.add(createauthorref(author));
 }
 
 private authorref createauthorref(author author) {
 
  assert.notnull(author, "author must not be null");
  assert.notnull(author.id, "author id, must not be null");
 
  authorref authorref = new authorref();
  authorref.authorid = author.id;
  return authorref;
 }
}
 
@table("book_author")
class authorref {
 long authorid ;
}
 
class author {
 @id long id;
 string name;
}

請注意額外的類:authorref,它表示有關(guān)某個作者的book聚合的知識。它可能包含有關(guān)作者的其他聚合信息,然后實際上會在數(shù)據(jù)庫中重復(fù)。考慮到author數(shù)據(jù)庫可能與book數(shù)據(jù)庫完全不同,這會產(chǎn)生很多問題。

另請注意,authors是book 私有字段,authorref實例化在私有方法createauthorref中發(fā)生。因此聚合之外的任何內(nèi)容都不能直接訪問它。spring data jdbc絕不需要這樣做,但ddd鼓勵這么做。

下面是測試:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@test
public void booksandauthors() {
 
 author author = new author();
 author.name = "greg l. turnquist";
 
 author = authors.save(author);
 
 book book = new book();
 book.title = "spring boot";
 book.addauthor(author);
 
 books.save(book);
 
 books.deleteall();
 
 assertthat(authors.count()).isequalto(1);
}

上述完成了我們設(shè)想功能:刪除書籍后,并沒有將書籍作者數(shù)據(jù)表數(shù)據(jù)全部刪除,雖然作者是書籍的一個私有字段。

總結(jié)一下:

spring data jdbc不支持多對一或多對多關(guān)系。要對這些進(jìn)行建模,請使用id。

這鼓勵了領(lǐng)域模型的清晰模塊化。

通過類似的思路,避免雙向依賴。聚合內(nèi)部的引用是從聚合根到元素。聚合之間的引用使用只在一個關(guān)聯(lián)方向上使用id表示。此外,如果需要反向?qū)Ш剑堅诖鎯熘惺褂貌樵兎椒ā_@樣能清楚確定哪個聚合負(fù)責(zé)維護(hù)引用。

banq注:是不是每個實體都需要一個對應(yīng)數(shù)據(jù)表?根據(jù)具體情況,order和orderitem之間生命周期是一致的,刪除訂單,訂單條目也沒有存在意義;而book和author則不是生命周期一致的,book可能是當(dāng)前有界上下文的聚合根,而author是另外一個有界上下文如作者管理系統(tǒng)的聚合根,如果刪除book同時,也將author刪除,其實是不符合要求的,這時候應(yīng)該將author作為值對象看待,author的id就是一個值,然后建立一個類authorref ,包含這個值,作為被book引用的對象,這樣就不是整個author實體聚合對象被book引用了。

以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持服務(wù)器之家。

原文鏈接:https://www.jdon.com/50192

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 金莲你下面好紧夹得我好爽 | 亲爱的客栈第二季免费观看完整版 | 情欲满载2012美国dvd | 亚洲九九精品 | 亚洲成人99 | 人人擦 | 福利视频一区二区思瑞 | 欧美日韩在线成人看片a | 亚洲国产cao | 无限好资源免费观看 | 暖暖中国免费观看高清完整版 | 男人网站视频 | 舔比小说| 欧美激情精品久久久久久不卡 | 99精品在线| 国产目拍亚洲精品一区二区三区 | 女人和男人搞基 | 性导航h| 国产亚洲精品91 | 好大好硬好深好爽gif图 | 亚洲精品tv久久久久久久久久 | 国产亚洲精品第一综合另类 | 久久亚洲一级α片 | 日韩精品在线视频观看 | 亚洲春色综合另类网蜜桃 | 欧美日韩视频在线第一区二区三区 | 美女福利视频网站 | 日本高清视频在线免费观看 | 青春草在线观看视频 | 草莓在深夜释放自己软件 | 亚洲视频一区网站 | 小嫩videos| 日本一道高清不卡免费 | 亚洲一区 在线播放 | 美女和男人免费网站视频 | 男同志gays| 国产精品久久久久久久久免费观看 | 久久中文字幕无线观看 | 久久青青草原精品国产软件 | 99视频九九精品视频在线观看 | 日韩亚洲欧美理论片 |