DuplicateItemException: duplicate primary key
TL;DR — PartiQL INSERT 是一次严格的创建:如果具有相同主键的项目已经存在,DynamoDB 会抛出 DuplicateItemException 而不是覆盖它。要修改现有项目,请使用 PartiQL UPDATE;要获得 PutItem 的"存在则替换"语义,请使用 PutItem 本身——PartiQL INSERT 特意从不替换。
含义
DuplicateItemException: There was an attempt to insert an item with the
same primary key as an item that already exists in the DynamoDB table.PartiQL 数据平面(ExecuteStatement / ExecuteTransaction / BatchExecuteStatement)把 INSERT 映射为一次条件创建——只有当不存在具有该主键的项目时它才成功。这与原生 PutItem 的默认行为相反,后者会静默地替换一个已有的项目。如果你来自 SQL 并期望 INSERT 在键重复时失败,这正是那个行为;如果你期望的是 upsert 语义,那这个错误就是意外。
为什么会发生
- 项目确实已经存在——一次重试、一次重放,或两个写入者在同一个键上竞速,都发出了
INSERT。 - 你想要的是更新,而非创建——把
PutItem风格的代码移植到 PartiQL,并假定INSERT会替换。 - 一个非幂等的重试循环——第一次尝试成功了但响应丢失了(超时),重试又重新插入了同一个键。
- 一个并不唯一的合成键——你组合的分区键/排序键碰撞的频率比你想象的更高(例如一个秒级精度的时间戳)。
如何修复
在更新现有项目?使用
UPDATE:UPDATE "orders" SET status = 'shipped' WHERE pk = 'ORDER#123' AND sk = 'META'想要"存在则替换"(PutItem 语义)?调用
PutItem——PartiQL 没有 upsert 语句,而原生 API 的默认行为正是你想要的覆盖:await client.send(new PutItemCommand({TableName: 'orders', Item: item}));当创建是幂等的时,把它当作成功——如果一次重试对你第一次尝试已经写入的项目遇到
DuplicateItemException,捕获并忽略它往往是正确的处理方式。当你依赖唯一性时保留
INSERT——这个异常就是你的仅创建守卫,是PutItem条件上attribute_not_exists()的 PartiQL 等价物。
对着真实数据尝试语句是内化 INSERT/UPDATE 之分的最快方式——DynoTable 桌面应用在一个 SQL 工作台中对你的实时表运行 PartiQL,而当你需要 PutItem 语义时,DynamoDB Expression Builder 会发出等价的原生 API 请求。
相关错误
- ConditionalCheckFailedException——原生 API 的孪生:
PutItem上失败的attribute_not_exists()守卫。 - ValidationException: Unexpected from source——另一个常见的 PartiQL 拒绝。
- 学习:PartiQL examples · PartiQL vs SQL
References
- ExecuteStatement — Amazon DynamoDB API Reference (DuplicateItemException)
- PartiQL insert statements for DynamoDB — Developer Guide
- PartiQL update statements for DynamoDB — Developer Guide
最后核实于 2026-07-13,依据上方链接的 AWS 官方文档。