本地DynamoDB条件写入报错:Exists为true时需提供AssetLabel值
问题描述
在本地DynamoDB执行更新操作时触发如下错误:
One or more parameter values were invalid: Value must be provided when Exists is true for Attribute: AssetLabel (Service: null; Status Code: 400; Error Code: ValidationException; Request ID: null; Proxy: null)
[junit] com.amazonaws.AmazonServiceException: One or more parameter values were invalid: Value must be provided when Exists is true for Attribute: AssetLabel (Service: null; Status Code: 400; Error Code: ValidationException; Request ID: null; Proxy: null)
已确认对象中存在assetLabel属性,但错误仍提示该属性缺失,相关代码如下:
测试代码
@Test public void testExecuteBackfill() throws FileNotFoundException { // Setup AssetRecord assetDetailsRecord = createAssetDetailsRecord(TestConstants.ASSET_LABEL_1, AssetStatusBO.ACTIVE); localDynamoMapper.save(assetDetailsRecord); // Assert Asset mapping unchanged AssetRecord fetchedAssetMappingRecord = loadAssetRecord(TestConstants.ASSET_LABEL_1, TestConstants.RANGE_KEY_LATEST); // Assert Asset detail changes AssetRecord fetchedAssetDetailsRecord = loadAssetRecord(TestConstants.ASSET_LABEL_1, TestConstants.RANGE_KEY_LATEST); System.out.println("fetchedAssetDetailsRecord = " +fetchedAssetDetailsRecord); //Mockito.when(assetDAO.getAssetByAssetLabel(TestConstants.ASSET_LABEL_1)).thenReturn(TestConstants.ASSET_BO); remarksAndMonitoringStatusBackfillerScriptHelper.executeBackfill(TEST_IOT_DATA_FILE_PATH); // Assert Asset detail changes fetchedAssetDetailsRecord = loadAssetRecord(TestConstants.ASSET_LABEL_1, TestConstants.RANGE_KEY_LATEST); }
建表代码
private void createTable() { final CreateTableRequest createTableRequest = localDynamoMapper.generateCreateTableRequest(AssetRecord.class); createTableRequest.setProvisionedThroughput(new ProvisionedThroughput(1L, 1L)); createTableRequest.getGlobalSecondaryIndexes().forEach(index -> { index.setProjection(new Projection().withProjectionType("ALL")); index.setProvisionedThroughput(new ProvisionedThroughput(1L, 1L)); }); localDynamo.createTable(createTableRequest); }
实体类代码
@Getter @Setter @Builder @NoArgsConstructor @AllArgsConstructor(access = AccessLevel.PRIVATE) @DynamoDBTable(tableName = AssetRecordConstants.TABLE_NAME) public class AssetRecord { @DynamoDBHashKey(attributeName = AssetRecordConstants.ASSET_LABEL) private String assetLabel; @DynamoDBRangeKey(attributeName = AssetRecordConstants.RANGE_KEY) private String rangeKey; @DynamoDBAttribute(attributeName = AssetRecordConstants.NODE_ID) @DynamoDBIndexHashKey(globalSecondaryIndexNames = {AssetRecordConstants.ASSET_TYPE_INDEX, AssetRecordConstants.MAPPED_RESOURCE_LABEL_INDEX}) private String nodeId; @DynamoDBTypeConvertedEnum @DynamoDBAttribute(attributeName = AssetRecordConstants.ASSET_TYPE) @DynamoDBIndexRangeKey(globalSecondaryIndexName = AssetRecordConstants.ASSET_TYPE_INDEX) private AssetTypeBO assetType; }
问题分析
这个错误的核心逻辑是:当更新请求中指定某个属性Exists=true(即判断该属性存在)时,必须同时提供该属性的具体值。即便你确认对象存在assetLabel,问题大概率出在executeBackfill方法的更新请求构建环节:
- 更新请求中使用了
attribute_exists(AssetLabel)的条件表达式,但未在请求的Key或ExpressionAttributeValues中传入AssetLabel的具体值; - 使用DynamoDB Mapper更新时,构建的
AssetRecord对象虽然逻辑上包含assetLabel,但实际序列化时该属性被忽略(比如Builder模式创建时未赋值、字段为空、注解配置冲突); assetLabel是表的HashKey,更新时必须通过它定位条目,若更新时未正确传递HashKey,也会触发此类验证错误。
解决方案
- 检查
executeBackfill的更新逻辑:- 若使用
UpdateItemRequest,确保当ConditionExpression包含attribute_exists(AssetLabel)时,Key参数已正确设置AssetLabel的值,或在ExpressionAttributeValues中提供对应取值; - 若使用DynamoDB Mapper的
save/update方法,确认待更新的AssetRecord对象的assetLabel属性已正确赋值,且无@DynamoDBIgnore等注解意外标记该字段。
- 若使用
- 验证Builder创建逻辑:实体类用了
@Builder,检查更新时构建对象是否通过assetLabel(xxx)方法显式赋值,避免私有全参构造导致属性未初始化。 - 开启请求日志排查:打开DynamoDB的请求日志,查看实际发送的更新请求参数,确认
AssetLabel是否真的被包含在请求中,快速定位问题点。
内容的提问来源于stack exchange,提问作者yogas
相关产品推荐
相关产品推荐

