14

是否有人对 AWS Java SDK 1.4.2(及更高版本)中的 DynamoDB 的新命名空间 ( com.amazonaws.services.dynamodbv2) 和接口进行了更改?根据1.4.2 发行说明,本地二级指数的发布显然需要进行重大更改。

有没有人找到详细说明发生了什么变化以及迁移现有代码需要发生什么的指南?我正在尝试决定何时最好对现有代码库进行此更改。

4

2 回答 2

18

DynamoDB的新dynamodbv2命名空间引入了以下不兼容的更改(因为它们不仅仅是附加的,并且需要更改代码才能切换到新的命名空间):

  • HashKeyElementRangeKeyElement被替换为Map<String, AttributeValue>。这包括名为ExclusiveStartKeyLastEvaluatedKeyKey的结构。此更改对代码的主要影响是现在为了调用GetItem,例如,您的代码需要知道主键的属性名称,而不仅仅是主键值。
  • Query 现在使用Map<String, Condition>类型的KeyCondition来指定完整的查询,而不是使用单独的HashKeyValueRangeKeyCondition字段。
  • CreateTable 输入将属性类型定义与主键定义分开(并且创建/更新/删除/描述响应与此匹配)
  • 响应中的已消耗容量现在是一个结构而不是单个数字,并且必须在请求中提出。在批处理操作中,它以单独的ConsumedCapacity结构返回,而不是与结果一起返回。

如果需要,可以逐步将您的代码迁移到新的 Java API。如果您计划在代码中添加查询本地二级索引或使用本地二级索引创建表的功能,您将需要为该部分代码使用新的 API。

如果您使用新 API 创建具有本地二级索引的表,您仍然可以使用dynamodb命名空间中的现有代码对该表执行所有现有操作。例如,具有dynamodb命名空间客户端的 PutItem 将针对使用dynamodbv2客户端创建的表工作,反之亦然。

于 2013-05-17T21:31:44.197 回答
9

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")));
于 2013-05-17T21:32:00.180 回答