专栏首页IT技能应用Spring Data JDBC、引用和聚合
原创

Spring Data JDBC、引用和聚合

之前的博客文章中,我、描述了如何设置和使用 Spring Data JDBC。我还描述了使 Spring Data

原标题:Spring认证|Spring Data JDBC、引用和聚合

JDBC 比 JPA 更容易理解的前提。一旦您考虑参考资料,这就会变得有趣。作为第一个示例,请考虑以下域模型:

class PurchaseOrder {

private @Id Long id;

private String shippingAddress;

private Set 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 {

@Query("select count(*) from order_item")

int countItems();

}

如果您创建一个包含商品的订单,您可能希望所有订单都能够持久化。这正是发生的事情:

@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,其所有项目也应被删除。再一次,事情就是这样。

repository.delete(saved);

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

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

}

但是,如果我们考虑句法相同但语义不同的关系呢?

class Book {

// …

Set authors = new HashSet();

}

当一本书绝版时,您将其删除。所有的作者都走了。当然不是你想要的,因为一些作者可能也写了其他书。现在,这没有意义。或者是吗?我认为确实如此。

为了理解为什么这确实有意义,我们需要退后一步,看看哪些存储库实际存在。这与一个反复出现的问题密切相关:您是否应该在 JPA 中每个表有一个存储库?

而正确且权威的答案是“NO”。存储库持久化并加载聚合。聚合是形成一个单元的一组对象,它应该始终保持一致。此外,它应该始终保持(和加载)在一起。它有一个对象,称为聚合根,它是唯一允许接触或引用聚合内部的对象。聚合根是传递给存储库以持久化聚合的内容。

这带来了一个问题:Spring Data JDBC 如何确定哪些是聚合的一部分,哪些不是?答案很简单:您可以通过遵循非瞬态引用从聚合根访问的所有内容都是聚合的一部分。

考虑到这一点, 的行为是OrderRepository完全合理的。 OrderItem实例是聚合的一部分,因此会被删除。 Author相反,实例不是Book聚合的一部分,因此不应被删除。所以他们不应该被Book类引用。

问题解决了。嗯,...不是真的。我们仍然需要存储和访问有关之间的关系的信息Book和Author。答案可以再次在领域驱动设计 (DDD) 中找到,它建议使用 ID 而不是直接引用。这适用于各种多对 x 关系。

如果多个聚合引用同一个实体,则该实体不能成为引用它的聚合的一部分,因为它只能是一个聚合的一部分。因此,任何多对一和多对多关系都必须仅通过引用 id 来建模。

如果你应用这一点,你可以实现多项目标:

您清楚地表示了聚合的边界。

您还完全解耦(至少在应用程序的域模型中)涉及的两个聚合。

这种分离可以在数据库中以不同的方式表示:

保持数据库的正常状态,包括所有外键。这意味着您必须确保以正确的顺序创建和保存聚合。

使用延迟约束,仅在事务的提交阶段进行检查。这可能会实现更高的吞吐量。它还编纂了最终一致性的一个版本,其中“最终”与事务的结束相关联。这也允许引用从不存在的聚合,只要它只在事务期间发生。这对于避免大量基础设施代码只是为了满足外键和非空约束可能很有用。

完全删除外键,实现真正的最终一致性。

将引用的聚合保留在不同的数据库中,甚至可能是 No SQL 存储。

无论您采取何种分离方式,即使是 Spring Data JDBC 强制执行的最低限度的分离,也会鼓励您的应用程序模块化。此外,如果您尝试过迁移一个真正有 10 年历史的单体应用程序,您就会了解它的价值。

使用 Spring Data JDBC,您可以对多对多关系进行建模,如下所示:

class Book {

private @Id Long id;

private String title;

private Set 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.author = author.id;

  return authorRef;

}

}

@Table("Book_Author")

class AuthorRef {

Long author;

}

class Author {

@Id Long id;

String name;

}

注意额外的类 ( AuthorRef),它代表 Book 聚合关于作者的知识。它可能包含有关作者的其他聚合信息,然后这些信息实际上会在数据库中复制。考虑到作者数据库可能与书籍数据库完全不同,这有很多事情要做。

另请注意,作者集是一个私有字段,实例的AuthorRef实例化发生在私有方法中。所以聚合之外的任何东西都不能直接访问它。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);

}

总结一下:Spring Data JDBC 不支持多对一或多对多关系。为了对这些进行建模,请使用 ID。这鼓励了领域模型的干净模块化。它还消除了人们必须解决的一整套问题,并学习推理这种映射是否可行。

按照类似的思路,避免双向依赖。聚合内的引用从聚合根到元素。聚合之间的引用由一个方向的 ID 表示。此外,如果您需要反向导航,请使用存储库中的查询方法。这使得明确无误地明确哪个聚合负责维护引用。

以下是示例使用的数据库结构。

Purchase_Order (

id

shipping_address

)

Order_Item (

purchase_order

quantity

product

);

Book (

id

title

)

Author (

id

name

)

Book_Author (

book

author

)

完整的示例代码可在Spring中国教育管理中心(Spring认证)数据示例库访问!

原创声明,本文系作者授权云+社区发表,未经许可,不得转载。

如有侵权,请联系 yunjia_community@tencent.com 删除。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • Spring Data JDBC - 如何使用自定义 ID 生成

    原标题:Spring认证|Spring Data JDBC-如何使用自定义ID生成

    IT胶囊
  • Spring模块组成(框架组成、整体架构、体系架构、体系结构)

    Spring 总共大约有 20 个模块, 由 1300 多个不同的文件构成。 而这些组件被分别整合在核心容器(Core Container) 、 AOP(Asp...

    Java_老男孩
  • 使用Spring Boot开发的10个免费开源项目

    本文推荐一些使用Spring Boot开发的免费开源项目,可用于学习目的,能够查看源代码并获得真实项目的实践经验。除了Spring Boot,您还将学习Spri...

    lyb-geek
  • Spring 中的 JDBC

      JDBC(Java Data Base Connectivity)是一种用于执行 SQL 语句的 Java APl,可以为多种关系型数据库提供统一访问,它是...

    Demo_Null
  • 《Spring实战》摘录 - 30

    Q: #21.1-1 | 在Spring家族中,Spring Boot是令人兴奋(也许我敢说它是改变游戏规则的)的新项目。它提供了四个主要的特性,能够改变开发S...

    用户1335799
  • Java匹马行天下之J2EE框架开发——Spring—>Spring框架知多少

    ————也许我注定成不了一个伟大的人,但是至少我可以做一个很棒的自己。我想我现在应该做的不是瞻前顾后,而是活在当下,正确认知自己,做好自己现在的工作,努力提升自...

    泰斗贤若如
  • Spring 的整体架构

    上图是 Spring 的整体框架图,主要分为了几大块: Core Container、Data Access/Integration、Web、AOP 和 Tes...

    飞翔的竹蜻蜓
  • 听说过spring-data-jdbc么?来个最佳实践

    很多人知道Mybatis,知道Jpa,但对2019年新诞生的一门技术知之甚少。那就是:spring-data-jdbc。这个标题起的很普通,但是内容绝对是最新的...

    xjjdog
  • Spring整合Sharding-JDBC分库分表详情

    最初线上系统的业务量不是很大,业务数据量并不大,比如说单库的数据量在百万级别以下(事实上千万级别以下都还能支撑),那么MySQL的单库即可完成任何增/删/改/查...

    品茗IT
  • SpringBoot 数据篇之使用JDBC

    Spring Data 包含对 JDBC 的存储库支持,并将自动为 CrudRepository 上的方法生成 SQL。对于更高级的查询,提供了 @Query ...

    静默虚空
  • springboot之整合基本的jdbc并操作Mysql数据库

    对于数据访问层,无论是SQL还是NOSQL,springboot默认采用整合spring data方式进行统一处理,添加大量自动配置,屏蔽了许多设置,引入各种x...

    西西嘛呦
  • Spring学习笔记1_Spring的概述

    本章目录 Spring学习笔记1_Spring的概述 1.Spring介绍 2.Spring作用 3.Spring起源 4.Spring体系结构 5.Spri...

    Java学习
  • 面试官三连问:你这个数据量多大?分库分表怎么做?用的哪个组件?

    ShardingSphere是一套开源的分布式数据库中间件解决方案组成的生态圈,它由Sharding-JDBC、Sharding-Proxy和Sharding-...

    芋道源码
  • sharding-jdbc金融支付项目中的应用(技术创作101训练营)

    初次接触shardingsphere是在2017年,那时候还叫sharding-jdbc,属于当当网。当时公司的支付项目改动升级,主要有如下两个问题。

    三复
  • 54 个官方 Spring Boot Starers 出炉!别再重复造轮子了……

    在之前的文章,栈长介绍了 Spring Boot Starters,不清楚的可以点击链接进去看下。

    Java技术栈
  • Java面试题| 框架篇

    最近小编时常会收到一些用户的后台留言,比如:“面试”、“2020”、“2020 Java”、“面试题”等等,追溯了下源头,原来就是几周前发布的《Java面试题大...

    IT大咖说
  • Spring技术内幕:设计理念和整体架构概述

    二十三年蝉
  • SpringBoot入门建站全系列(二十四)使用Sharding-JDBC进行分库分表

    一个系统最初的线上业务量并不会很大,比如说单库的数据量在百万级别以下(事实上千万级别以下都还能支撑),那么MySQL的单库即可完成任何增/删/改/查的业务操作。...

    品茗IT
  • SpringBoot入门建站全系列(二十四)使用Sharding-JDBC进行分库分表

    一个系统最初的线上业务量并不会很大,比如说单库的数据量在百万级别以下(事实上千万级别以下都还能支撑),那么MySQL的单库即可完成任何增/删/改/查的业务操作。...

    品茗IT

扫码关注云+社区

领取腾讯云代金券