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。
我正在尝试将项目放入 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。