2

这里是 DynamoDB 菜鸟,有兴趣了解 NoSQL 数据库。

我有一个场景,我有一个表,它有一个 userId 的分区键、一个时间的排序键和一个数字句柄。句柄是一个递增 1 的顺序计数器。

以下是该表的示例:

userId, time, handle
0     , 123 , 1
0     , 456 , 2
1     , 123 , 1
1     , 234 , 2
0     , 789 , 3
1     , 345 , 3

对于给定的 userId,句柄不能有重复项

我想要做的是为 userId 0 添加一条新记录,时间为 891,并且句柄 1 大于 userId 0 的最后写入记录 - 这将是数据库中的倒数第二行,即 3 + 1 = 4。

天真的方法是查询数据库的 userId 为 0,按最后一个时间戳排序(如果可能的话)以获取句柄 (3)。这是第一个请求。然后,您将在数据库上创建一个 put_item 请求,该请求将 1 添加到句柄 (3 + 1 = 4) 并创建一条新记录。

显然这里存在竞争条件,在读取查询和创建 put_item 请求之间,另一个 lambda/API/endpoint 可能已经使用相同的句柄 (4) 向数据库提交了一条新记录,例如 (1, 888, 4) . 当我提交原始记录 (0, 891, 4) 时,句柄是 4,而现在应该是 5。

是否可以在单个事务中执行此读写操作(也许我的心态错误)。

如果我的问题不清楚,请告诉我。

4

2 回答 2

1

您可能需要第二个表来保存一个原子计数器,该计数器保存每个 userId 的最高句柄。当您需要添加记录时,您可以原子地增加第二个表中 userId 的计数器,然后从计数器中获取值并将其用于新记录。

于 2018-09-20T01:09:33.717 回答
1

您正在尝试做的事情:“分配一个单调递增的数值作为唯一标识符”是分布式数据库(noSql 或其他)的反模式

花点时间考虑一下这个问题。

如果您可以使用 GUID 作为唯一标识符,那么您不再需要查询来确定上次使用的标识符,并且始终保证唯一值。

如果您需要 ID 具有某种顺序概念,那么您应该考虑一种策略,通过该策略从时间戳和一些小的随机值生成 Id。如果您尝试插入具有重复标识符的记录,您只需重试。

否则,使用任意单调递增整数的方法是将它们存储在用户级别(同一张表或单独),但每次更新用户记录时,您将更新相同的键,因此您失去了可伸缩性。

最后 - 如果对于每个用户,您只有很少数量的记录要存储,请考虑将这些记录组合成单个项目的模式。

于 2018-09-20T16:31:30.387 回答