最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

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

 更新時間:2018年09月30日 11:32:59   作者:解道  
這篇文章主要介紹了使用Spring Data JDBC實(shí)現(xiàn)DDD聚合的示例代碼,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧

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

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

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;
}

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

interface OrderRepository extends CrudRepository<PurchaseOrder, Long> {

 @Query("select count(*) from order_item")
 int countItems();
}

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

@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,它的所有項(xiàng)目也應(yīng)該被刪除。

 …
 repository.delete(saved);

 assertThat(repository.count()).isEqualTo(0);
 assertThat(repository.countItems()).isEqualTo(0);
}

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

class Book {
 // …
 Set<Author> authors = new HashSet<>();
}

當(dāng)書籍絕版時,將Book刪除。所有的作者Author也都丟失了。這當(dāng)然不是你想要的,因?yàn)橐恍┳髡呖赡芤矊戇^其他書。

怎么辦?

讓我們看一看存儲庫實(shí)際存在的內(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實(shí)例是聚合的一部分,因此被刪除; Author正好相反,實(shí)例不是Book聚合的一部分,因此不應(yīng)刪除。所以不應(yīng)該從Book內(nèi)部去引用那些作者Author對象。

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

如果多個聚合引用同一個實(shí)體,則該實(shí)體不能成為引用它的多個聚合的一部分,因?yàn)樗荒苁瞧渲幸粋€聚合的一部分。因此,任何“多對一”和“多對多”關(guān)系都只能通過引用id來建模實(shí)現(xiàn)了。

這樣可以實(shí)現(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. 完全刪除外鍵,實(shí)現(xiàn)真正的最終一致性。

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

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

使用Spring Data JDBC,您可以建模多對多關(guān)系,如下所示:

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í)際上會在數(shù)據(jù)庫中重復(fù)??紤]到Author數(shù)據(jù)庫可能與Book數(shù)據(jù)庫完全不同,這會產(chǎn)生很多問題。

另請注意,authors是Book 私有字段,AuthorRef實(shí)例化在私有方法createAuthorRef中發(fā)生。因此聚合之外的任何內(nèi)容都不能直接訪問它。Spring Data JDBC絕不需要這樣做,但DDD鼓勵這么做。

下面是測試:

@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ū)Ш剑堅(jiān)诖鎯熘惺褂貌樵兎椒?。這樣能清楚確定哪個聚合負(fù)責(zé)維護(hù)引用。

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

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

相關(guān)文章

  • Java使用Collections.sort()排序的方法

    Java使用Collections.sort()排序的方法

    這篇文章介紹了Java使用Collections.sort()排序的方法,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-12-12
  • Spring?cloud?Hystrix注解初始化源碼過程解讀

    Spring?cloud?Hystrix注解初始化源碼過程解讀

    這篇文章主要為大家介紹了Hystrix初始化部分,我們從源碼的角度分析一下@EnableCircuitBreaker以及@HystrixCommand注解的初始化過程,有需要的朋友可以借鑒參考下,希望能夠有所幫助
    2023-12-12
  • Spring?中使用?Validation?注解校驗(yàn)參數(shù)的方法

    Spring?中使用?Validation?注解校驗(yàn)參數(shù)的方法

    本文介紹了如何在Spring中使用Validation注解進(jìn)行參數(shù)校驗(yàn),包括引入依賴、簡單示例、常見校驗(yàn)注解分類與說明、分組校驗(yàn)和自定義校驗(yàn),通過這些方法,可以方便地對Controller、Service等層面的參數(shù)進(jìn)行校驗(yàn),確保數(shù)據(jù)的合法性和一致性,感興趣的朋友跟隨小編一起看看吧
    2024-11-11
  • Hadoop之常用端口號解讀

    Hadoop之常用端口號解讀

    這篇文章主要介紹了Hadoop之常用端口號,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2023-11-11
  • 在日志中記錄Java異常信息的正確姿勢分享

    在日志中記錄Java異常信息的正確姿勢分享

    這篇文章主要介紹了在日志中記錄Java異常信息的正確姿勢,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-09-09
  • java實(shí)現(xiàn)爬取知乎用戶基本信息

    java實(shí)現(xiàn)爬取知乎用戶基本信息

    這篇文章主要為大家介紹了一個基于JAVA的知乎爬蟲,抓取知乎用戶基本信息,感興趣的小伙伴們可以參考一下
    2016-05-05
  • java類中生成jfreechart,返回圖表的url地址 代碼分享

    java類中生成jfreechart,返回圖表的url地址 代碼分享

    這篇文章介紹了java類中生成jfreechart,返回圖表的url地址的代碼,有需要的朋友可以參考一下
    2013-08-08
  • JAVA求兩直線交點(diǎn)和三角形內(nèi)外心的方法

    JAVA求兩直線交點(diǎn)和三角形內(nèi)外心的方法

    本文提供了JAVA求兩直線交點(diǎn)、三角形外心、三角形內(nèi)心的代碼和算法講解,大家可以參考使用
    2013-11-11
  • java實(shí)現(xiàn)ATM機(jī)系統(tǒng)(2.0版)

    java實(shí)現(xiàn)ATM機(jī)系統(tǒng)(2.0版)

    這篇文章主要為大家詳細(xì)介紹了java實(shí)現(xiàn)ATM機(jī)系統(tǒng)2.0版,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-03-03
  • maven package 打包報(bào)錯 Failed to execute goal的解決

    maven package 打包報(bào)錯 Failed to execute goal的解決

    這篇文章主要介紹了maven package 打包報(bào)錯 Failed to execute goal的解決,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-11-11

最新評論

白玉县| 白河县| 新宁县| 淳安县| 于田县| 牡丹江市| 博湖县| 新营市| 故城县| 广州市| 南岸区| 建水县| 鹿泉市| 加查县| 钟祥市| 乌审旗| 石棉县| 浦北县| 中江县| 威信县| 枣庄市| 稷山县| 霍州市| 遂川县| 高台县| 东明县| 仙桃市| 开原市| 临朐县| 九龙县| 靖安县| 高要市| 翼城县| 鹤岗市| 阳谷县| 临湘市| 肇源县| 岢岚县| 临夏市| 观塘区| 诸城市|