异步航行 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;
})
})
})
您的 Season
和 Episode
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 块。
使用 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;
})
})
})
您的 Season
和 Episode
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 块。