在并发和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()
这是在单元测试中发生的。其想法是强制并发出现故障,因为两个“Execs”试图更新同一行,以确保给出正确的冲突错误响应。然而,第二个“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驱动程序处理连接池的方式漏掉了什么?为什么第二次事务执行会被阻塞,直到第一个事务提交?事务不是两者可以同时运行,先提交(或开始?)的那个获胜吗?
*DB
对象可用于管理多个连接,您的驱动程序可能限制为一个连接,或者并不设计打开新连接,每个驱动程序都有自己的实现,它们的列表可以在这里找到:https://github.com/golang/go/wiki/SQLDrivers - evanmcdonnal