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

在AWS DynamoDB中插入关联项前如何校验父项存在性

如何在DynamoDB事务中校验客户与产品的存在性

业务场景与问题

业务中一个订单可包含多个产品,且归属单个客户,订单、产品、客户均存储在同一张DynamoDB表中。创建订单的请求格式如下:

{
    "customer_id": "c8fb0e64-43b0-45b1-a9e7-fe2ce61c2c1f",
    ...
    "products": [
        {
            "id": "7362ea92-2063-48ad-9bfe-c91a5d9af4a6",
            ...
        },
        {
            "id": "83e38b2f-2839-43c5-a834-0834d841e566",
            ...
        }
    ]
}

当前使用TransactWriteItems创建订单的代码可正常执行,但未校验客户及关联产品的存在性:

  • 需校验请求中指定的客户是否存在
  • 需校验请求中所有关联产品是否存在

表结构说明:

  • 客户可通过part_key和/或customer_id字段识别,_type属性值为customer
  • 产品可通过part_key和/或product_id字段识别,_type属性值为product

需要在事务插入订单数据前完成上述存在性校验,要求兼顾性能与成本。

最优解决方案

利用DynamoDB TransactWriteItems支持的ConditionCheck操作,在事务中原子执行存在性校验与数据插入。ConditionCheck会先验证指定条件,只有所有校验通过,后续的Put操作才会执行;任意校验失败,整个事务回滚,无数据写入。

具体实现步骤

  1. 添加客户存在性校验:
    构造ConditionCheck项,指定客户的主键(示例中假设客户的part_key为customer#<customer_id>,sort_key与part_key一致),通过条件表达式确保该条目存在且为客户类型。

  2. 添加产品存在性校验:
    对每个关联产品,构造对应的ConditionCheck项,指定产品的主键(示例中假设产品的part_key为product#<product_id>,sort_key与part_key一致),验证条目存在且为产品类型。

  3. 整合事务操作:
    将所有ConditionCheck与原有的订单、订单-产品关联数据的Put操作放入同一个事务请求中,保证原子性。

修改后的Go代码

func (d DynamoDB) CreateOrder(ctx context.Context, model database.Order) error {
    items := make([]types.TransactWriteItem, 0, len(model.Products)*2 + 2) // 预留校验与写入的位置

    // 1. 校验客户存在性
    customerKey := database.Key{
        PartKey: "customer#" + model.CustomerID,
        SortKey: "customer#" + model.CustomerID,
    }
    customerItem, err := attributevalue.MarshalMap(customerKey)
    if err != nil {
        return err
    }
    items = append(items, types.TransactWriteItem{
        ConditionCheck: &types.ConditionCheck{
            TableName: aws.String(d.Table),
            Key:       customerItem,
            ConditionExpression: aws.String("attribute_exists(_type) AND _type = :customer_type"),
            ExpressionAttributeValues: map[string]types.AttributeValue{
                ":customer_type": &types.AttributeValueMemberS{Value: "customer"},
            },
        },
    })

    // 2. 校验每个产品的存在性
    for _, product := range model.Products {
        productKey := database.Key{
            PartKey: "product#" + product.ID,
            SortKey: "product#" + product.ID,
        }
        productItem, err := attributevalue.MarshalMap(productKey)
        if err != nil {
            return err
        }
        items = append(items, types.TransactWriteItem{
            ConditionCheck: &types.ConditionCheck{
                TableName: aws.String(d.Table),
                Key:       productItem,
                ConditionExpression: aws.String("attribute_exists(_type) AND _type = :product_type"),
                ExpressionAttributeValues: map[string]types.AttributeValue{
                    ":product_type": &types.AttributeValueMemberS{Value: "product"},
                },
            },
        })
    }

    // 3. 添加订单-产品关联数据
    for _, product := range model.Products {
        product.Key = database.Key{
            PartKey: "order#" + product.OrderID,
            SortKey: "product#" + product.ID,
        }
        product.Type = "order_product"

        item, err := attributevalue.MarshalMap(product)
        if err != nil {
            return err
        }

        items = append(items, types.TransactWriteItem{
            Put: &types.Put{
                TableName: aws.String(d.Table),
                Item:      item,
            },
        })
    }

    // 4. 添加订单主数据
    model.Key = database.Key{
        PartKey: "order#" + model.ID,
        SortKey: "order#" + model.ID,
    }
    model.Type = "order"

    item, err := attributevalue.MarshalMap(model)
    if err != nil {
        return err
    }

    items = append(items, types.TransactWriteItem{
        Put: &types.Put{
            TableName: aws.String(d.Table),
            Item:      item,
        },
    })

    _, err = d.Client.TransactWriteItems(ctx, &dynamodb.TransactWriteItemsInput{
        TransactItems: items,
    })
    if err != nil {
        return err
    }

    return nil
}

注意事项

  • 若你的表中客户或产品的主键结构与示例不同(比如sort_key为其他固定值),请调整customerKey和productKey的构造逻辑,确保能准确定位到对应条目。
  • 条件表达式中加入_type校验,是为了避免主键冲突导致的误判(比如避免把其他类型的条目当成客户/产品)。
  • DynamoDB事务最多支持25个操作,若订单关联产品数量较多,需注意此限制,超过时可拆分事务处理。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.18 07:01:15