Postgresql 事务查看开始后对数据库行所做的更改

Postgresql 事务查看开始后对数据库行所做的更改,postgresql,go,transactions,isolation-level,go-gorm,Postgresql,Go,Transactions,Isolation Level,Go Gorm,在与博士后和Go GORM一起工作时,我发现了一些我无法理解的事情 在下面的代码段中,我尝试查找、删除和创建同一项,但在两个不同的事务中,但是我开始第二个事务,并在提交第一个事务之前找到该项 在第二个事务中,发生了一些奇怪的事情。当我调用t2.Delete()时,它不会删除任何行。在数据库中,调用t1.Commit()后,该项的主键变为2,但由于它已经获得了旧项,因此它删除了主键1 为什么事务2会看到新行,尽管它是在提交第一行之前创建的? db,err:=gorm.Open(“postgres”

在与博士后和Go GORM一起工作时,我发现了一些我无法理解的事情

在下面的代码段中,我尝试查找、删除和创建同一项,但在两个不同的事务中,但是我开始第二个事务,并在提交第一个事务之前找到该项

在第二个事务中,发生了一些奇怪的事情。当我调用
t2.Delete()
时,它不会删除任何行。在数据库中,调用
t1.Commit()
后,该项的主键变为
2
,但由于它已经获得了旧项,因此它删除了主键
1

为什么事务2会看到新行,尽管它是在提交第一行之前创建的?

db,err:=gorm.Open(“postgres”,“host=localHost-port=5432 user=postgres-dbname=test-password=postgres-sslmode=disable”)
延迟db.Close()
db.DropTableIfExists(&Product{})
db.AutoMigrate(&Product{})
db.LogMode(真)
db.Create(&产品{代码:“A”,价格:1000})
//SQL:在“产品”(“代码”、“价格”)中插入返回“产品”的值('A',1000)。“id”
//启动事务1,查找项目,将其删除
t1:=db.Begin()
产品:=&产品{}
err=t1.Find(产品,“代码=?”,“A”).Error
//SQL:从“产品”中选择*,其中(代码='A')
err=t1。删除(产品)。错误
//SQL:从“产品”中删除,其中“产品”。“id”=1
//在事务1创建新项目并提交之前,启动事务2并获取项目
t2:=db.Begin()
产品2:=&产品{}
err=t2.Find(产品2,“代码=?”,“A”).Error
//SQL:从“产品”中选择*,其中(代码='A')
err=t1.Create(&Product{Code:“A”,Price:3000})。错误
//SQL:在“产品”(“代码”、“价格”)中插入返回“产品”的值('A',3000)。“id”
err=t1.Commit().Error
//数据库现在包含
err=t2。删除(product2)。错误
//SQL:从“产品”中删除,其中“产品”。“id”=1
//[0行受影响或返回]
err=t2.Save(&Product{Code:“A”,Price:4000})。错误
//SQL:在“产品”(“代码”、“价格”)中插入返回“产品”的值('A',4000)。“id”
//此处错误:pq:重复键值违反唯一约束“产品\代码\键值”
err=t2.Commit().Error
注意:GORM默认使用
读取提交的隔离级别
。我知道如果它工作正常,会导致完整性问题。我将改为使用
Serializable
,这将在提交时给出一个错误,或者在Get时阻塞,如果指定
“用于更新;”

来自PostgreSQL

Read Committed是PostgreSQL中的默认隔离级别。当 事务使用此隔离级别,即SELECT查询(不带FOR) UPDATE/SHARE子句)只查看查询开始前提交的数据; 它从未看到未提交的数据或在提交过程中提交的更改 通过并发事务执行查询。实际上,一个SELECT查询 在查询开始时查看数据库的快照 跑

还要注意,两个连续的SELECT命令可以看到不同的数据, 即使它们在单个事务中,如果其他 事务在第一次选择开始之后和之前提交更改 第二次选择开始

第二段似乎总结了你的情况。在提交
t1
之后启动的
t2
中的任何“选择”都可以看到
t1
应用的更新