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

DQL mutation添加重复记录未触发@id唯一约束如何解决?

问题原因

  • GraphQL Schema 中定义的 @id 字段唯一约束,是Dgraph GraphQL API 层单独实现的校验逻辑,仅作用于通过 GraphQL 入口提交的请求,不会下沉到 DQL 底层自动生效。
  • DQL Schema 里的 @upsert 索引本身不具备强制唯一的能力,它的作用是配合 Upsert 操作保证并发写入时冲突检测的正确性,不会主动阻止重复数据写入。
  • 你通过 dgo 直接提交 DQL mutation 时,既绕开了 GraphQL 层的校验逻辑,又使用了不带冲突检查的普通 mutation,因此会出现重复插入的情况。

解决方法

可根据业务场景选择以下两种方案:

方案1:使用 DQL Upsert Mutation 代替普通 Mutation

自行在 mutation 前添加查询逻辑,检查目标字段是否已存在对应值,仅当无重复时执行写入,参考逻辑如下:

// 构造 Upsert 请求
query := `
query checkDuplicate($name: string, $slug: string) {
  var(func: eq(Product.name, $name)) {
    nameCount as count(uid)
  }
  var(func: eq(Product.slug, $slug)) {
    slugCount as count(uid)
  }
  isDuplicate() {
    duplicate: math(max(val(nameCount), val(slugCount)))
  }
}
`
mutation := &api.Mutation{
  SetNquads: []byte(`
    _:newProduct <Product.name> "your_product_name" .
    _:newProduct <Product.slug> "your_product_slug" .
    _:newProduct <Product.image> "your_image_url" .
    _:newProduct <Product.created_at> "2024-01-01T00:00:00Z" .
    _:newProduct <Product.updated_at> "2024-01-01T00:00:00Z" .
    _:newProduct <dgraph.type> "Product" .
  `),
  // 仅当无重复时执行写入
  Cond: `@if(eq(val(duplicate), 0))`,
}
req := &api.Request{
  Query: query,
  Vars: map[string]string{
    "$name": "your_product_name",
    "$slug": "your_product_slug",
  },
  Mutations: []*api.Mutation{mutation},
  CommitNow: true,
}
// 执行请求后判断写入结果,若 Upsert 条件不满足会返回无修改结果,自行抛出唯一性冲突错误即可

该方案可以保证即使在高并发场景下,也不会出现重复数据,@upsert 索引会保障 Upsert 操作的原子性。

方案2:业务层前置校验

写入前先查询确认 name 和 slug 无重复,再执行写入操作。该方案适合并发量较低的场景,高并发场景下需要额外加分布式锁避免竞态条件导致的重复写入。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.01 01:09:03