是否有人对 AWS Java SDK 1.4.2(及更高版本)中的 DynamoDB 的新命名空间 ( com.amazonaws.services.dynamodbv2
) 和接口进行了更改?根据1.4.2 发行说明,本地二级指数的发布显然需要进行重大更改。
有没有人找到详细说明发生了什么变化以及迁移现有代码需要发生什么的指南?我正在尝试决定何时最好对现有代码库进行此更改。
是否有人对 AWS Java SDK 1.4.2(及更高版本)中的 DynamoDB 的新命名空间 ( com.amazonaws.services.dynamodbv2
) 和接口进行了更改?根据1.4.2 发行说明,本地二级指数的发布显然需要进行重大更改。
有没有人找到详细说明发生了什么变化以及迁移现有代码需要发生什么的指南?我正在尝试决定何时最好对现有代码库进行此更改。
DynamoDB的新dynamodbv2命名空间引入了以下不兼容的更改(因为它们不仅仅是附加的,并且需要更改代码才能切换到新的命名空间):
如果需要,可以逐步将您的代码迁移到新的 Java API。如果您计划在代码中添加查询本地二级索引或使用本地二级索引创建表的功能,您将需要为该部分代码使用新的 API。
如果您使用新 API 创建具有本地二级索引的表,您仍然可以使用dynamodb命名空间中的现有代码对该表执行所有现有操作。例如,具有dynamodb命名空间客户端的 PutItem 将针对使用dynamodbv2客户端创建的表工作,反之亦然。
DynamoDB AWS Java 1.4.1 => 1.4.2(非详尽)迁移步骤
好吧,我硬着头皮做到了。这是我的经验。
首先,更改 DynamoDB 命名空间:
com.amazonaws.services.dynamodb
=>com.amazonaws.services.dynamodbv2
您注意到的第一件事是缺少类型。最重要的是Key不见了。很好摆脱,因为它的名字太笼统了。它现在被 Map 取代,这很有意义,因为本地二级索引(LSI) 的键变得更具可塑性。不幸的是,在 Java 中使用映射和泛型通常很糟糕(见底部的奖励)。withHashKeyElement
/的流畅接口已经一去不复返了withRangeKeyElement
。
接下来,非常仔细地查找/替换被通用集合替换的 DynamoDB 类型:
com.amazonaws.services.dynamodb.model.Key
=>Map<String, AttributeValue>
com.amazonaws.services.dynamodb.model.BatchResponse
=>List<Map<String, AttributeValue>>
com.amazonaws.services.dynamodb.model.KeySchema
=>List<KeySchemaElement>
接下来,找到所有损坏的东西。这是一个非常手动的过程,需要非常了解您的代码库和 SDK。具体来说,您必须非常了解您的密钥架构,因为从这里开始它都是字符串。幸运的是,在我的情况下,前两个任务是大约 90% 的更改:
new Map<String, AttributeValue>
,它是一个Key
以前存在的迹象。QueryRequest
合并withHashKeyValue(AttributeValue)
withRangeKeyCondition(Condition)
到 megawithKeyConditions(Map<String,Condition>)
这个方法是 LSI 的核心变化,允许您指定除哈希/范围以外的内容。它接受的内容比接口更具限制性,但当您考虑 DynamoDB 仅允许您查询索引属性时,这是合乎逻辑的。DynamoDBQueryExpression
变得通用并改变了它的界面(不知道为什么)。KeySchemaElement
不再需要AttributeType
,但现在需要KeyType
最后,编译和回归测试你的整个堆栈。
PS 在我执行所有这些操作时,1.4.4.1 版本刚刚发布到 Maven Central。
奖金
由于 Map 是 Java 缺乏松散类型类的常见解决方案,因此它们无处不在。一个小助手库真的可以大大减少构建这些冗长的方法。以下是我的助手的一些内容:
public class MakeJavaSuckLess { // TODO: find a shorter class name
public static final float MAX_LOAD_FACTOR = 1.0f;
/**
* Builds a mutable Map from an interlaced sequence of key-value pairs
* where keys are strings and values are VType objects
* @param pairs
* @return
*/
public static <VType> Map<String, VType> asMap(Object... pairs) {
return mergeMaps(null, pairs);
}
/**
* Builds a mutable Map from an interlaced sequence of key-value pairs
* where keys are strings and values are VType objects
* @param pairs
* @return
*/
public static <VType> Map<String, VType> mergeMaps(Map<String, VType> map, Object... pairs) {
final int length = (pairs != null) ? pairs.length/2 : 0;
if (map == null) {
// max out the load factor since most of these don't change
map = new HashMap<String, VType>(length, MAX_LOAD_FACTOR);
}
for (int i=0; i<length; i++) {
String key = asString(pairs[2*i]);
@SuppressWarnings("unchecked")
VType value = (VType)pairs[2*i+1];
map.put(key, value);
}
return map;
}
}
现在创建您的 DynamoDB 密钥稍微不那么难看了:
Map<String, AttributeValue> key = MakeJavaSuckLess.asMap("hashKey", new AttributeValue("hashVal"), "rangeKey", new AttributeValue("rangeVal"));
Java 泛型中的类型擦除使这在某些地方再次变得丑陋。您有时需要明确指定VType
:
new GetItemRequest().withKey(MakeJavaSuckLess.<AttributeValue>asMap("hashKey", new AttributeValue("hashVal"), "rangeKey", new AttributeValue("rangeVal")));