【问题标题】:How to model many to many relationship in DynamoDB with Java SDK如何使用 Java SDK 在 DynamoDB 中建模多对多关系
【发布时间】:2019-08-28 16:16:45
【问题描述】:

我看过一些关于 DynamoDB 多对多关系的文章。

据我了解; 应该有一个表,我需要使用复合主键。

对于书籍项目; hashKey(partionKey) 应该是 book id;并且 RangeKey(sortKey) 应该是作者 ID; 对于作者项目; hashKey(partionKey) 应该是作者 id;并且 RangeKey(sortKey) 应该是 book id;

我已经创建了这些模型;

 @Data
 @DynamoDBTable(tableName = "author_book_table")
 public class Book {

    @Id
    private BookId id;

    private String name;

    private Integer pages;

 }



@Data
@DynamoDBTable(tableName = "author_book_table")
public class Author {

    @Id
    private AuthorId id;
    @DynamoDBAttribute
    private String name;

}

Id 模型如下所示;

@Data
public class BookId {

    @DynamoDBHashKey
    private String bookId;

    @DynamoDBRangeKey
    private String authorId;
}


@Data
public class AuthorId {
    @DynamoDBHashKey
    private String authorId;
    @DynamoDBRangeKey
    private String bookId;
}

但我无法想象如何使用它,如何查询作者的书籍或作者的书籍。 正确的做法是什么?

我在 java 上找不到任何关系示例。 我也使用 Spring data dynamoDB moodule。

【问题讨论】:

  • 我不确定我是否理解您的要求。你能给出一个示例数据库(只有几个条目),一个示例查询(单词很好)和预期的输出吗?
  • @MyStackRunnethOver 我有 Book 和 Author 实体,他们需要对多对多关系进行建模。我还需要按作者获取书籍并按书籍获取作者。我该怎么做。

标签: java spring-boot amazon-dynamodb


【解决方案1】:

[旁注:您确定 spring data dynamodb 模块允许您在同一张表上读取/写入两个不同的@Data 类吗?如果答案是“否”,那么您将需要使用两个单独的表格。无论如何,我的其余答案不受此影响(因为在使用其他 SDK 时,您当然可以在同一个 DDB 表中存储不止一种类型的项目]

我能想到四个用例:

(a) 给定作者的 ID,您想获取她写的所有书籍的 ID

(b) 给定作者的 ID,您想获取她写的所有书籍的名称

(c) 给定一本书的 ID,您想获取该书所有作者的 ID

(d) 给定您想要获取该书所有作者姓名的书的 ID

快速的答案是,鉴于此数据模型 (a) 和 (c) 可以通过单个查询轻松实现。但是,(b)和(d)不能通过单个查询来实现(参见下面的答案 1)。但是,DDB 中的“正确”方法是对事物进行不同的建模(参见下面的答案 2)

回答 1

here 所述,当您在 DDB 表上执行query 时,您可以给它一个分区键(又名:哈希键)。该查询将返回具有按范围键排序的分区键的所有项目。由于每个作者项目都有(作为范围键)书籍 ID,这意味着当您传入作者 ID 时,您将获得所有书籍 ID。同样,如果查询给定的图书 ID,您将获得所有作者 ID。

如果您还想获取书名(从给定的作者 ID),您必须首先获取所有书籍 ID(如上一段所述),然后使用 BatchGetItem 获取单个书籍项目。请注意BatchGetItemupper limit of 100 items,因此您可能需要多次调用BatchGetItem。 (当然,这个解决方案也适用于另一个方向:书籍 -> 作者,你只需要用作者精神替换书籍,反之亦然)

答案 2

在 DDB 和许多其他 NoSql 数据库中,您可以使用数据的非规范化(即跨多个项目复制同一条信息)来塑造数据,使其以适合您检索的方式存储用例。在这里,它归结为包含作者详细信息和书籍详细信息的单一类型的项目。

@Data
@DynamoDBTable(tableName = "author_book_table")
public class Book {

  @DynamoDBHashKey
  @DynamoDBIndexRangeKey(globalSecondaryIndexName="ByAuthor")
  private String bookId;

  @DynamoDBRangeKey
  @DynamoDBIndexHashKey(globalSecondaryIndexName="ByAuthor")
  private String authorId;

  private String bookName;
  private String authorName;
  private Integer pages;
}

使用此数据模型,您仍然可以查询对图书 ID 发出查询的图书的所有作者。查询结果返回的项目将包含所有作者姓名。对于另一个方向(作者 ID -> 书籍),您还需要执行查询,但这次针对您需要定义的全局二级索引 (ByAuthor)。在这个索引中,角色是相反的:作者 ID 是哈希键,书籍 ID 是范围键。

缺点是当一条数据发生变化时,你需要更新多条记录。例如,如果您需要将作者 ID“100”的名称从“Alice”更新为“Beth”,则需要找到 所有 个作者 ID 为“100”的项目并在那里更新作者姓名。同样,如果您需要更新表的数量,您将需要更新多个项目(如果这本书有三个作者,则需要更新三个具有该书 ID 的项目)。

重要提示:您可以从您的应用程序/服务中发布此更新。但是,您需要为您的服务(或底层硬件)在更新过程中失败的情况做好准备。这可能会导致数据不一致(在某些项目中作者姓名为“Beth”,但在某些项目中仍为“Alice”)。 Transaction 可以帮助您,但它们仅限于更新 25 个项目。如果您无法在单个事务中更新,则需要进行纠正测量:例如,您可以定期扫描数据库并修复您发现的任何不一致之处。最重要的是,您可以让服务在其“常规”操作期间主动检查其获取的项目中的不一致之处。如果发现不一致,它可以针对这些特定项目启动修复程序。

【讨论】:

    猜你喜欢
    • 2019-08-21
    • 2021-04-09
    • 2020-04-18
    • 2019-08-04
    • 2021-07-10
    • 1970-01-01
    • 1970-01-01
    • 2019-02-24
    相关资源
    最近更新 更多