[英]How can GORM's FirstOrCreate() method (or Django's get_or_create) ensure that just one row is created?
I'm considering using GORM for an application and was looking into how FirstOrCreate
works, and it seems that it uses two database operations.我正在考虑将 GORM 用于应用程序,并正在研究
FirstOrCreate
工作原理,它似乎使用了两个数据库操作。 Consider this example script:考虑这个示例脚本:
package main
import (
"github.com/jinzhu/gorm"
_ "github.com/jinzhu/gorm/dialects/sqlite"
"github.com/sirupsen/logrus"
)
type User struct {
gorm.Model
Name string
Age uint
}
func main() {
db, err := gorm.Open("sqlite3", "examplegorm.db")
if err != nil {
logrus.Fatalf("open db: %v", err)
}
defer db.Close()
db.LogMode(true)
db.AutoMigrate(&User{})
var user User
db.Where(User{Name: "non_existing"}).Attrs(User{Age: 20}).FirstOrCreate(&user)
}
Upon running this and inspecting the logs, I see that (aside from the auto-migration) it uses two queries, one SELECT
and one INSERT
:运行它并检查日志后,我看到(除了自动迁移)它使用两个查询,一个
SELECT
和一个INSERT
:
kurt@Kurts-MacBook-Pro-13 ~/D/Scratch> go run gorm_example.go
(/Users/kurt/Documents/Scratch/gorm_example.go:23)
[2020-01-05 09:09:10] [1.03ms] CREATE TABLE "users" ("id" integer primary key autoincrement,"created_at" datetime,"updated_at" datetime,"deleted_at" datetime,"name" varchar(255),"age" integer )
[0 rows affected or returned ]
(/Users/kurt/Documents/Scratch/gorm_example.go:23)
[2020-01-05 09:09:10] [0.86ms] CREATE INDEX idx_users_deleted_at ON "users"(deleted_at)
[0 rows affected or returned ]
(/Users/kurt/Documents/Scratch/gorm_example.go:26)
[2020-01-05 09:09:10] [0.28ms] SELECT * FROM "users" WHERE "users"."deleted_at" IS NULL AND (("users"."name" = 'non_existing')) ORDER BY "users"."id" ASC LIMIT 1
[0 rows affected or returned ]
(/Users/kurt/Documents/Scratch/gorm_example.go:26)
[2020-01-05 09:09:10] [0.31ms] INSERT INTO "users" ("created_at","updated_at","deleted_at","name","age") VALUES ('2020-01-05 09:09:10','2020-01-05 09:09:10',NULL,'non_existing',20)
[1 rows affected or returned ]
As I understand from https://stackoverflow.com/a/16128088/995862 , however,然而,据我了解https://stackoverflow.com/a/16128088/995862 ,
In a SQL DBMS, the select-test-insert approach is a mistake: nothing prevents another process from inserting the "missing" row between your
select
andinsert
statements.在 SQL DBMS 中,select-test-insert 方法是一个错误:没有什么可以阻止另一个进程在您的
select
和insert
语句之间插入“缺失”的行。
It seems that Django's get_or_create()
works in a similar fashion.似乎 Django 的
get_or_create()
以类似的方式工作。 Given this model,鉴于这个模型,
from django.db import models
class User(models.Model):
name = models.CharField(max_length=255)
age = models.PositiveIntegerField()
if I enable database logging and run a get_or_create()
query I see如果我启用数据库日志记录并运行
get_or_create()
查询,我会看到
In [1]: from djangoapp.models import *
In [2]: User.objects.get_or_create(name="jinzhu", age=20)
(0.000) SELECT "djangoapp_user"."id", "djangoapp_user"."name", "djangoapp_user"."age" FROM "djangoapp_user" WHERE ("djangoapp_user"."age" = 20 AND "djangoapp_user"."name" = 'jinzhu') LIMIT 21; args=(20, 'jinzhu')
(0.000) BEGIN; args=None
(0.000) INSERT INTO "djangoapp_user" ("name", "age") VALUES ('jinzhu', 20); args=['jinzhu', 20]
Out[2]: (<User: User object (1)>, True)
In short, if I want to be sure that only one record gets created, it seems that I should refrain from using an ORM such as GORM or the Django ORM and write my own query?简而言之,如果我想确保只创建一条记录,似乎我应该避免使用诸如 GORM 或 Django ORM 之类的 ORM 并编写自己的查询?
A second question I have is how to get the equivalent of Django's created
Boolean in GORM.我的第二个问题是如何在 GORM 中获得 Django
created
Boolean 的等价物。 Should I determine whether the RowsAffected
of the resulting gorm.DB
is 1
to determine whether a row was actually created or not?我应确定是否
RowsAffected
所产生的gorm.DB
为1
来确定行是否实际创建或不?
You should just add UNIQUE constraint on the query model fields and that would be enough to keep it consistent in db您应该只在查询模型字段上添加 UNIQUE 约束,这足以使其在 db 中保持一致
for Django that would be adding meta class to model对于将元类添加到模型的 Django
class Meta:
unique_together = ['name', 'age']
for GORM对于 GORM
Name string `gorm:"unique_index:idx_name_age"`
Age uint `gorm:"unique_index:idx_name_age"`
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.