GORM Playground Link
https://github.com/go-gorm/playground/pull/536
Description
Calling FirstOrCreate from multiple gouroutines for the same object results in a UNIQUE constraint failed error.
Note
Maybe FirstOrCreate is not supposed to be safe by choice, i couldn't find any mention of that except this https://github.com/go-gorm/gorm/issues/2760, if it is by design maybe mention that in the documentation? i found in v1 docs that "GORM is safe for concurrent use by multiple goroutines."
Comment From: a631807682
Errors can occur as long as the operation is not atomic for database, it has nothing to do with thread safety. The database may be changed by any process, you need to avoid it by locking.
Refer to the following pseudo code:
app1.Find
app2.Delete
app1.Update // throw err, record has been deleted
For gorm you can use OnConflict but it won't solve all problems.
tx := DB.Clauses(clause.OnConflict{
UpdateAll: true,
})
tx.FirstOrCreate(&languageCopy)
Comment From: YeahItsMeAgain
Seems i wasn't descriptive enough 😅 I was talking about the exact situation that i had written in my test, that an orm like django's solves with this logic (full code here):
try:
return self.get(**params)
except self.model.DoesNotExist:
try:
with transaction.atomic(using=self.db):
return self.create(**params)
except IntegrityError:
try:
return self.get(**params)
except self.model.DoesNotExist:
pass
raise
But after rethinking about it i suppose [locking the relevant pieces of code\using OnConflict to upsert relevant columns\handling the error in other ways] is much better and safer! thx :)