java如何在并发环境中获取DynamoDB中的下一个空闲项
我在DynamoDB中有一个表,其中有我的用户(Partial key=key,Sort key=no):
键激活
user1 true
用户2错误
在我的代码中,我需要返回状态为not active(isActive=false)的下一个用户。如果我需要解决方案,最好的方法是什么
- 一张大桌子
- 并发环境
我编写的代码可以工作,但由于扫描和筛选表达式的原因,我不确定它是否是一个好的解决方案:
public String getFreeUser() throws IOException {
Table table = dynamoDB.getTable("usersTableName");
ScanSpec spec = new ScanSpec()
.withFilterExpression("isActive = :is_active")
.withValueMap(new ValueMap().withBoolean(":is_active", false));
ItemCollection<ScanOutcome> items = table.scan(spec);
Iterator<Item> iterator = items.iterator();
Item item = null;
while (iterator.hasNext()) {
item = iterator.next();
try {
UpdateItemSpec updateItemSpec = new UpdateItemSpec()
.withPrimaryKey(new PrimaryKey("key", item.getString("key")))
.withUpdateExpression("set #ian=:is_active_new")
.withConditionExpression("isActive = :is_active_old")
.withNameMap(new NameMap()
.with("#ian", "isActive"))
.withValueMap(new ValueMap()
.withBoolean(":is_active_old", false)
.withBoolean(":is_active_new", true))
.withReturnValues(ReturnValue.ALL_OLD);
UpdateItemOutcome outcome = table.updateItem(updateItemSpec);
return outcome.getItem().getString("key");
} catch (Exception e) {
}
}
throw new IOException("No active users were found");
}
# 1 楼答案
GSI+Query==GOOD
添加哈希键为
isActive
的GSI。这将允许您直接查询isActive
==false
的项目与扫描和筛选相比,读取的好处是效率更高。成本是你的GSI需要它自己的存储,所以如果你的表很大(根据你的假设),那么你可能需要考虑一个稀疏索引。p>
稀疏索引GSI+Query==更好
考虑用^ {< CD5>}替换属性^ {CD1>},不要将此属性赋给活动用户。也就是说,非活动用户将具有
true
,但活动用户将根本不具有此属性。然后可以使用这个isNotActive
属性创建GSI。由于它只包含非活动用户,因此存储和查询将更小、更高效请注意,当用户处于活动状态时,您需要删除此属性,对于处于非活动状态的活动用户,则需要删除此属性
属性投影
无论您决定哪个GSI最适合您,如果您知道在查询这些非活动用户时需要哪些属性(即使只是“所有用户”),您可以将这些属性投影到您的GSI,这样您就不需要按键进行第二次查找。这将增加GSI的大小,但根据表大小、活动用户与非活动用户的比率以及预期的访问模式,这可能是一个值得权衡的问题
更新
作为对第一条评论的回应,需要澄清的是,GSI密钥(现在标记为“GSI-PK”)不是用户ID。我可以将
isActive
或active
列放在GSI表的最左边,但它在AWS控制台中不是这样显示的,因此为了与AWS的显示方式保持一致,我将其保留为原始顺序你是关于并发的第二条评论,你是对的,我没有提到这一点。我的解决方案将在并发环境中工作,除了一件事——您只能最终执行一致性读取,而不能执行强一致性读取。这意味着一个最近的非活动用户(在大多数情况下,我指的是几分之一秒)可能还没有复制到GSI。类似地,最近从非活动更改为活动的用户可能尚未更新GSI。您需要考虑最终一致阅读是否可用于您的用例。
另一个需要考虑的问题是,如果这将是一个非常大的表,如果查询结果将达到总计>;1MB无论如何都会得到分页结果,因为DynamoDB强制执行该限制。如果没有全局表锁,由于页面查询之间来自其他客户端的更新,您将获得一些不一致性,在这种情况下,最终一致读取将需要为您工作