遇到并发和 SQL 事务的问题。我有下面的(存根)代码(为了清楚起见,删除了错误检查和这样的代码):
dao, _ := sql.Open("postgres", args)
tx1 := dao.Begin()
res, _ := tx1.Exec("UPDATE <...>", args...)
// error check
tx2 := dao.Begin()
res, _ = tx2.Exec("UPDATE <same>", args...)
_ = tx1.Commit()
_ = tx2.Commit()
这发生在单元测试中。这个想法是强制并发失败,因为两个 Exec 正在尝试更新同一行,以确保给出正确的冲突错误响应。但是,第二个 Exec 永久阻塞。
据我所知,这种类型的阻塞只有在数据库没有数据库连接时才会发生,但事务都应该在它们自己的(独占)连接中运行,而且我没有在任何地方设置最大连接(我也试过将它设置为 100 之类的,没有效果)。
这是奇怪的部分。如果我将 tx2 Exec() 和 Commit() 分离到一个单独的 goroutine 中,并带有一个同步通道来阻止主线程运行 tx1.Commit() 直到 tx2 运行它的 Exec(),同样的事情会发生,无限期地阻塞tx2.Exec()。如果我使用 time.Sleep() 而不是同步通道,tx2.Exec 会阻塞,直到睡眠完成并运行 tx1.Commit(),然后以预期的错误 ( pq: could not serialize access due to concurrent update)
我是否遗漏了有关 golang 的 SQL 包或 postgres 驱动程序如何处理连接池的信息?为什么在提交第一个事务之前,第二个事务 Exec 会阻塞?两个事务可以同时运行,并且无论哪个提交(或者它开始?)首先获胜,这不是事务的重点吗?