You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用Java实现DynamoDB事务的存在更新/不存在插入操作?

问题:DynamoDB事务中实现"存在则更新,不存在则新增"的逻辑

我尝试通过DynamoDB更新事务操作数据表,需求为:若找到指定行则更新该行;若未找到则新增一行。我找到一段Java示例代码:

final String PRODUCT_TABLE_NAME = "ProductCatalog";
final String PRODUCT_PARTITION_KEY = "ProductId";
HashMap<String, AttributeValue> productItemKey = new HashMap<>();
productItemKey.put(PRODUCT_PARTITION_KEY, new AttributeValue(productKey));

Map<String, AttributeValue> expressionAttributeValues = new HashMap<>();
expressionAttributeValues.put(":new_status", new AttributeValue("SOLD"));
expressionAttributeValues.put(":expected_status", new AttributeValue("IN_STOCK"));

Update markItemSold = new Update()
    .withTableName(PRODUCT_TABLE_NAME)
    .withKey(productItemKey)
    .withUpdateExpression("SET ProductStatus = :new_status")
    .withExpressionAttributeValues(expressionAttributeValues)
    .withConditionExpression("ProductStatus = :expected_status")
    .withReturnValuesOnConditionCheckFailure(ReturnValuesOnConditionCheckFailure.ALL_OLD);

这段代码仅当ProductStatus当前为IN_STOCK时才会更新该行,否则不执行更新。我需要实现的逻辑是:判断分区键值是否存在,存在则更新,不存在则新增,请问该如何实现?


解决方案

DynamoDB的UpdateItem操作(对应Java SDK中的Update类)默认就支持Upsert(更新或插入)行为:当指定的主键(分区键+排序键,如果有)存在时,执行更新;不存在时,自动插入新项。

基础实现(通用Upsert)

直接修改现有代码,移除针对ProductStatus的条件判断,即可实现需求。如果需要在插入新项时填充更多字段,可在UpdateExpression中扩展字段定义。

final String PRODUCT_TABLE_NAME = "ProductCatalog";
final String PRODUCT_PARTITION_KEY = "ProductId";
HashMap<String, AttributeValue> productItemKey = new HashMap<>();
productItemKey.put(PRODUCT_PARTITION_KEY, new AttributeValue(productKey));

Map<String, AttributeValue> expressionAttributeValues = new HashMap<>();
// 定义需要更新的字段值,插入新项时这些字段也会被设置
expressionAttributeValues.put(":new_status", new AttributeValue("SOLD"));
// 可选:添加插入时需要的其他字段
// expressionAttributeValues.put(":new_price", new AttributeValue().withN("99.99"));

Update upsertItem = new Update()
    .withTableName(PRODUCT_TABLE_NAME)
    .withKey(productItemKey)
    // SET语句:更新指定字段,不存在则创建
    .withUpdateExpression("SET ProductStatus = :new_status")
    // 可选:扩展SET语句添加更多字段
    // .withUpdateExpression("SET ProductStatus = :new_status, Price = :new_price")
    .withExpressionAttributeValues(expressionAttributeValues)
    .withReturnValuesOnConditionCheckFailure(ReturnValuesOnConditionCheckFailure.ALL_OLD);

关键说明

  • 移除原代码的withConditionExpression("ProductStatus = :expected_status"),取消状态限制;
  • 默认逻辑下,Update操作会自动处理:
    • 主键存在:执行SET语句更新指定字段;
    • 主键不存在:创建新项,包含主键和SET语句中指定的所有字段。

进阶实现(区分更新/插入逻辑)

如果更新和插入需要执行不同的逻辑(比如设置不同字段),可以在事务中结合两个带条件的操作:

  1. 带attribute_exists(ProductId)条件的Update(仅主键存在时更新);
  2. 带attribute_not_exists(ProductId)条件的Put(仅主键不存在时插入)。

DynamoDB事务会自动执行符合条件的操作,另一个会因条件不满足被跳过,整体事务仍会成功提交。

// 1. 仅当主键存在时执行的更新操作
Map<String, AttributeValue> updateValues = new HashMap<>();
updateValues.put(":new_status", new AttributeValue("SOLD"));
Update updateExisting = new Update()
    .withTableName(PRODUCT_TABLE_NAME)
    .withKey(productItemKey)
    .withUpdateExpression("SET ProductStatus = :new_status")
    .withExpressionAttributeValues(updateValues)
    .withConditionExpression("attribute_exists(ProductId)")
    .withReturnValuesOnConditionCheckFailure(ReturnValuesOnConditionCheckFailure.ALL_OLD);

// 2. 仅当主键不存在时执行的插入操作
Map<String, AttributeValue> putItem = new HashMap<>();
putItem.put(PRODUCT_PARTITION_KEY, new AttributeValue(productKey));
putItem.put("ProductStatus", new AttributeValue("SOLD"));
// 添加插入时专属的字段
putItem.put("Price", new AttributeValue().withN("99.99"));
putItem.put("CreateTime", new AttributeValue().withS(LocalDateTime.now().toString()));
Put insertNew = new Put()
    .withTableName(PRODUCT_TABLE_NAME)
    .withItem(putItem)
    .withConditionExpression("attribute_not_exists(ProductId)")
    .withReturnValuesOnConditionCheckFailure(ReturnValuesOnConditionCheckFailure.ALL_OLD);

// 组装并执行事务
TransactWriteItemsRequest transactionRequest = new TransactWriteItemsRequest()
    .withTransactItems(Arrays.asList(
        new TransactWriteItem().withUpdate(updateExisting),
        new TransactWriteItem().withPut(insertNew)
    ));

dynamoDbClient.transactWriteItems(transactionRequest);

内容的提问来源于stack exchange,提问作者mnk802

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.16 23:01:24