ValidationException: ExpressionAttributeNames 只能在使用 DynamoDB Put 使用表达式时指定

ValidationException: ExpressionAttributeNames can only be specified when using expressions using DynamoDB Put

我正在尝试将项目放入 DynamoDB table。我基本上是将更新项目的使用与放置项目交换,其逻辑与下面完全相同,但对于放置项目,我收到错误:

ValidationException: ExpressionAttributeNames can only be specified when using expressions

代码如下:

// Puts/updates item into DynamoDB table
public boolean setSessionString(String sessionId, String clientDomain, Map<String, String> keyValueMap,
                                long ttl) {

    // TTL since epoch calculation
    long timeToLiveInSeconds = ttl == 0 ? DEFAULT_TTL : ttl;
    long expirationTime = System.currentTimeMillis() / 1000L + timeToLiveInSeconds;

    try {
        // Construct putItemSpec
        PutItemSpec putItemSpec = createPutItemSpec(
                createPrimaryKey(sessionId, clientDomain), keyValueMap, expirationTime);

        table.putItem(putItemSpec);
        return true;

    } catch (final Exception e) {
        throw DependencyException.builder()
              .withMessage("DynamoDB update/put item error: " + e.getMessage())
              .withCause(e.getCause())
              .build();
    }
}

// Enumerate key-value pairs to escape DynamoDB reserved keyword
private PutItemSpec createPutItemSpec(PrimaryKey primaryKey, Map<String, String> keyValueMap, long expirationTime) {
    Item item = new Item().withPrimaryKey(primaryKey);
    PutItemSpec putItemSpec = new PutItemSpec();

    List<String> keyList = new ArrayList<String>(keyValueMap.keySet());
    NameMap nameMap = new NameMap();
    ValueMap valueMap = new ValueMap();

    // Enumerating key-value entries
    for (int keyValueIndex = 0; keyValueIndex < keyList.size(); keyValueIndex++) {
        String keyEnum = "#k" + keyValueIndex;
        String valueEnum = ":v" + keyValueIndex;
        String key = keyList.get(keyValueIndex);
        nameMap.with(keyEnum, key);
        valueMap.with(valueEnum, keyValueMap.get(key));
    }

    // Appending ttl attribute
    String ttlAttributeEscape = "#" + RESERVED_TTL_ATTRIBUTE;
    String ttlValueEscape = ":" + RESERVED_TTL_ATTRIBUTE;
    nameMap.with(ttlAttributeEscape, RESERVED_TTL_ATTRIBUTE);
    valueMap.withLong(ttlValueEscape, expirationTime);

    return putItemSpec.withNameMap(nameMap)
                      .withValueMap(valueMap)
                      .withItem(item);
}

对我可能遗漏的内容有什么建议吗? update 和 put item spec 之间可能有一个关键的区别。

您没有使用最新的 Amazon DynamoDB API 将项目放入 Amazon DynamoDB table。推荐的方法是使用 AWS SDK for Java V2 和 Enchanced Client。使用增强客户端,您可以简单地创建一个 Java POJO,使用它的方法设置值,然后简单地调用 putItem 方法并传递 Java 对象。 (您不需要使用 LISTS 等)

此处的文档:

Mapping items in DynamoDB tables

这是一个 Java V2 示例:

package com.example.dynamodb;

// snippet-start:[dynamodb.java2.mapping.putitem.import]
import software.amazon.awssdk.enhanced.dynamodb.DynamoDbEnhancedClient;
import software.amazon.awssdk.enhanced.dynamodb.DynamoDbTable;
import software.amazon.awssdk.enhanced.dynamodb.TableSchema;
import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.DynamoDbSortKey;
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.dynamodb.DynamoDbClient;
import software.amazon.awssdk.services.dynamodb.model.DynamoDbException;
import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.DynamoDbBean;
import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.DynamoDbPartitionKey;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
// snippet-end:[dynamodb.java2.mapping.putitem.import]

/*
 * Prior to running this code example, create an Amazon DynamoDB table named Customer with these columns:
 *   - id - the id of the record that is the key
 *   - custName - the customer name
 *   - email - the email value
 *   - registrationDate - an instant value when the item was added to the table
 *
 * Also, ensure that you have setup your development environment, including your credentials.
 *
 * For information, see this documentation topic:
 *
 * https://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/get-started.html
 */
public class EnhancedPutItem {

    public static void main(String[] args) {

        Region region = Region.US_EAST_1;
        DynamoDbClient ddb = DynamoDbClient.builder()
                .region(region)
                .build();

        DynamoDbEnhancedClient enhancedClient = DynamoDbEnhancedClient.builder()
                .dynamoDbClient(ddb)
                .build();

        putRecord(enhancedClient) ;
        ddb.close();
    }

    // snippet-start:[dynamodb.java2.mapping.putitem.main]
    // Puts an item into a DynamoDB table
    public static void putRecord(DynamoDbEnhancedClient enhancedClient) {

        try {
            DynamoDbTable<Customer> custTable = enhancedClient.table("Customer", TableSchema.fromBean(Customer.class));

            // Create an Instant
            LocalDate localDate = LocalDate.parse("2020-04-07");
            LocalDateTime localDateTime = localDate.atStartOfDay();
            Instant instant = localDateTime.toInstant(ZoneOffset.UTC);

            // Populate the Table
            Customer custRecord = new Customer();
            custRecord.setCustName("Susan red");
            custRecord.setId("id140");
            custRecord.setEmail("sred@noserver.com");
            custRecord.setRegistrationDate(instant) ;

            // Put the customer data into a DynamoDB table
            custTable.putItem(custRecord);

        } catch (DynamoDbException e) {
            System.err.println(e.getMessage());
            System.exit(1);
        }
        System.out.println("done");
    }
    // snippet-end:[dynamodb.java2.mapping.putitem.main]
}

这里是对应的CustomerClass;

package com.example.dynamodb;

import software.amazon.awssdk.enhanced.dynamodb.DynamoDbEnhancedClient;
import software.amazon.awssdk.enhanced.dynamodb.DynamoDbTable;
import software.amazon.awssdk.enhanced.dynamodb.TableSchema;
import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.DynamoDbBean;
import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.DynamoDbPartitionKey;
import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.DynamoDbSortKey;
import software.amazon.awssdk.enhanced.dynamodb.model.BatchWriteItemEnhancedRequest;
import software.amazon.awssdk.enhanced.dynamodb.model.WriteBatch;
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.dynamodb.DynamoDbClient;
import software.amazon.awssdk.services.dynamodb.model.DynamoDbException;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneOffset;

/**
 * This class is used by the Enhanced Client examples.
 */

 @DynamoDbBean
 public class Customer {

        private String id;
        private String name;
        private String email;
        private Instant regDate;

        @DynamoDbPartitionKey
        public String getId() {
            return this.id;
        };

        public void setId(String id) {

            this.id = id;
        }

        public String getCustName() {
            return this.name;
        }

        public void setCustName(String name) {
            this.name = name;
        }

        public String getEmail() {
            return this.email;
        }

        public void setEmail(String email) {
            this.email = email;
        }

        public Instant getRegistrationDate() {
            return regDate;
        }
        public void setRegistrationDate(Instant registrationDate) {

            this.regDate = registrationDate;
        }
    }

您可以找到更多 Enhanced Client examples here

此外,您可以在 AWS SDK Github 存储库中找到一个 AWS 教程,该教程显示了在使用 Spring BOOT 开发的动态 Web 应用程序中如何使用此 API .

Creating the DynamoDB web application item tracker

有资源告诉你如何使用最新的Amazon DynamoDB API。