异步航行 findOrCreate returns "record already exists" if 运行

Sails findOrCreate returns "record already exists" if running asynchronously

使用 sails.js,我有一个服务正在使用 .findOrCreate(...)

如果使用相同的数据同时调用此服务两次,则会 returns 出现 "record already exists" 错误。

这是一个已知问题吗?有什么克服它的建议吗?

更新:

我正在使用 sails-mysql。
查询字段设置为唯一(这就是我收到此错误的原因,否则会创建重复项)并且还设置为索引(如 Waterline docs 中的建议)

更新二:

Show.js:

tmdbId: {
  type: 'integer',
  unique: true,
  index: true
},
name: {
  type: 'string',
  required: true
},
slug: {
  type: 'string',
  required: true,
  unique: true
},
seasons: {
  collection: 'season',
  via: 'show'
},
episodes: {
  collection: 'episode',
  via: 'show'
}

服务:

Show.findOrCreate({
  tmdbId: req.tmdbId
}, {
  tmdbId: req.tmdbId,
  name: req.showName,
  slug: Services.slug(req.showName)
}).exec(function (err, show) {
  if (err)
    return sails.log.error(err);
  Season.findOrCreate({
    show: show.id,
    number: req.season
  }).exec(function (err, season) {
    if (err)
      return sails.log.error(err);
    Episode.findOrCreate({
      show: show.id,
      season: season.id,
      number: req.episode,
      airDate: req.airDate
    }).exec(function (err, episode) {
      if (err)
        return sails.log.error(err);
      return res;
    })
  })
})

您的 SeasonEpisode findOrCreate 不遵循 Sails 惯例。尝试:

Show
    .findOrCreate({
      tmdbId: req.tmdbId
    }, {
      tmdbId: req.tmdbId,
      name: req.showName,
      slug: Services.slug(req.showName)
    })
    .exec(function (err, show) {
      if (err) return sails.log.error(err);

      Season
        .findOrCreate({
          show: show.id
        }, {
          show: show.id,
          number: req.season
        })
        .exec(function (err, season) {
          if (err) return sails.log.error(err);

          Episode
          .findOrCreate({
            show: show.id
          }, {
            show: show.id,
            season: season.id,
            number: req.episode,
            airDate: req.airDate
          })
          .exec(function (err, episode) {
            if (err) return sails.log.error(err);

            return res;
          })
        })
    })

我在使用 postgres 适配器时遇到了同样的问题,我认为原因是竞争条件。这似乎是一个已知问题:Waterline Docs: findOrCreate broken with high frequency calls #929

findOrCreate 似乎不是原子的,所以我认为发生的情况是第一次调用执行了一个 find 查询,在执行创建操作之前 returns 没有结果.如果第二个调用在第一个调用的 create 完成之前执行它的 find,它也会 return 一个空结果,触发另一个 create.

如果 create 数据包含唯一值,则会出现此问题。由于执行了两次 create 操作,因此将添加两次相同的数据,因此第二次失败,因为数据库中已存在唯一值。如果没有标记为 unique 的值,则结果是重复的。

解决此问题的一种方法是捕获错误并在 catch 块中执行 find 查询,因为我们知道该条目现在存在,然后是您打算首先执行的任何操作.不幸的是,这种方法在您的示例中确实变得非常丑陋,因为嵌套的 findOrCreate 调用每个都需要自己的 catch 块。