在Golang中使用SQL事务进行批量插入或更新操作。

huangapple go评论82阅读模式
英文:

bulk upserts within a sql transaction in golang

问题

我一直在使用Golang的sql包和事务进行实验,并且我正在尝试理解如何进行批量插入更新,而不需要每行进行“每次插入”的往返通信。这里的示例并没有真正展示如何执行任何批量查询。

理想情况下,我希望能够使用准备好的查询,并构建一个要同时发送的插入更新列表...但是在这里,我们在每次执行后都会从数据库获取一个结果。有关如何处理此问题的任何建议吗?

编辑:
我的同事找到了这个描述问题的开放票证,它似乎是一个比仅仅在事务上下文中更大的问题。

英文:

I've been messing around with golang's sql package with transactions, and I'm trying to understand how to do bulk upserts without the "per insert" round trip communication for each row. The examples here don't really show how any bulk queries would be done.

updateMoney, err := db.Prepare("INSERT INTO balance set money=?, id=? ON DUPLICATE UPDATE balance SET money=money+? WHERE id=?")
...
tx, err := db.Begin()
...
res, err := tx.Stmt(updateMoney).Exec(123.45, 1, 123.45, 1)
res, err := tx.Stmt(updateMoney).Exec(67.89, 2, 67.89, 2)
res, err := tx.Stmt(updateMoney).Exec(10.23, 3, 10.23, 3)
...
tx.Commit()

Ideally, I'd be able to take a prepared query, and build up a list of upserts to be sent at the same time... but here, we get a result back from the database after each execution. Any suggestions on how to go about this?

Edit:
My coworker found this open ticket that describes the problem... it looks to be a larger concern than strictly within the context of a transaction.

答案1

得分: 10

这取决于你使用的驱动程序,有些驱动程序/数据库根本不支持事务。

例如,go-sql-driver/mysql 很好地支持事务。

你的代码应该可以工作,或者你可以稍微修改一下:

tx, err := db.Begin()
...
stmt, err := tx.Prepare(`INSERT INTO balance set money=?, id=? ON DUPLICATE UPDATE balance SET money=money+? WHERE id=?`)
res, err := stmt.Exec(123.45, 1, 123.45, 1)
res, err := stmt.Exec(67.89, 2, 67.89, 2)
res, err := stmt.Exec(10.23, 3, 10.23, 3)
...
tx.Commit()

还可以查看这个答案,其中详细介绍了事务。

英文:

It depends on which driver you are using, some drivers / databases don't support transactions at all.

For example go-sql-driver/mysql supports transactions just fine.

Your code should work, or you could change it a little to:

tx, err := db.Begin()
...
stmt, err := tx.Prepare(`INSERT INTO balance set money=?, id=? ON DUPLICATE UPDATE balance SET money=money+? WHERE id=?`)
res, err := stmt.Exec(123.45, 1, 123.45, 1)
res, err := stmt.Exec(67.89, 2, 67.89, 2)
res, err := stmt.Exec(10.23, 3, 10.23, 3)
...
tx.Commit()

Also check this answer which goes into a lot of details about transactions.

答案2

得分: 4

所以,虽然我们无法为每个upsert执行单独的查询,但我们可以在单个语句中编写有效的MySQL代码来进行批量upsert操作...

INSERT INTO balance (id, money) VALUES (1, 123.45), (2, 67.89), (3, 10.23)
ON DUPLICATE KEY UPDATE money = money + values(money)

因此,对于任何想要进行批量upsert操作的人来说,有一种模式可以解决MySQL驱动程序的任何限制。

英文:

So while we weren't able to do separate queries for each upsert, we did write valid mysql for bulk upserts in a single statement...

INSERT INTO balance (id, money) VALUES (1, 123.45), (2, 67.89), (3, 10.23)
ON DUPLICATE KEY UPDATE money = money + values(money)

So for anyone who wants to do a bulk upsert, there is a pattern to work around any limitations of the mysql driver.

huangapple
  • 本文由 发表于 2014年8月13日 23:00:18
  • 转载请务必保留本文链接:https://go.coder-hub.com/25289593.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定