如何使用Java SDK在DynamoDB中建立多对多关系模型

时间:2019-08-26 22:22:59

标签: java spring-boot amazon-dynamodb

我已经阅读了一些有关DynamoDB manyToMany关系的文章。

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

对于书籍项目;  hashKey(partionKey)应该是书的ID;和RangeKey(sortKey)应该是作者ID; 对于作者项目;  hashKey(partionKey)应该是作者ID;和RangeKey(sortKey)应该是书籍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数据dynamoDB moodule。

1 个答案:

答案 0 :(得分:0)

[旁注:您确定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调用。 (当然,此解决方案也可以在另一个方向上起作用:book-> author,您只需要在心理上将作者替换为author,反之亦然)

答案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'的 all 项目,并在那里更新作者名称。同样,如果您需要更新表的数量,则需要更新多个项目(如果这本书有三位作者,那么将需要更新具有该书ID的三个项目)。

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