英文:
Idiomatic way to do multiple queries in golang in one transaction
问题
我目前正在努力(第二天)寻找最佳的多查询方法,想知道你是否知道解决方案。
我有一个名为myDb的开放sql.DB连接,并使用go-sql-driver*。
func TruncateGalleryImport() error {
s := make([]string, 0)
s = append(s, "TRUNCATE TABLE add_map")
s = append(s, "TRUNCATE TABLE album")
s = append(s, "TRUNCATE TABLE album_permission")
s = append(s, "TRUNCATE TABLE album_view")
s = append(s, "TRUNCATE TABLE album_watch")
s = append(s, "TRUNCATE TABLE media")
s = append(s, "TRUNCATE TABLE media_user_view")
s = append(s, "TRUNCATE TABLE media_view")
s = append(s, "TRUNCATE TABLE media_watch")
s = append(s, "TRUNCATE TABLE private_map")
s = append(s, "TRUNCATE TABLE attachment")
s = append(s, "TRUNCATE TABLE attachment_data")
for _, q := range s {
_, err := myDb.Exec(q)
if err != nil {
return err
}
}
return nil
}
是否可能使用一个事务将上述所有查询一起提交?
祝好!
英文:
I'm currently struggling (my 2nd day) to find the best way to do multiple queries and was wondering if you know a solution.
I have an open *sql.DB Connection, named myDb and use the go-sql-driver
func TruncateGalleryImport() error {
s := make([]string, 0)
s = append(s, "TRUNCATE TABLE add_map")
s = append(s, "TRUNCATE TABLE album")
s = append(s, "TRUNCATE TABLE album_permission")
s = append(s, "TRUNCATE TABLE album_view")
s = append(s, "TRUNCATE TABLE album_watch")
s = append(s, "TRUNCATE TABLE media")
s = append(s, "TRUNCATE TABLE media_user_view")
s = append(s, "TRUNCATE TABLE media_view")
s = append(s, "TRUNCATE TABLE media_watch")
s = append(s, "TRUNCATE TABLE private_map")
s = append(s, "TRUNCATE TABLE attachment")
s = append(s, "TRUNCATE TABLE attachment_data")
for _, q := range s {
_, err := myDb.Exec(q)
if err != nil {
return err
}
}
return nil
}
Is it possible to commit all the above queries together using only one transaction?
Cheers
答案1
得分: 9
使用事务,像这样(请参阅代码中的注释):
func TruncateGalleryImport() error {
s := make([]string, 0)
s = append(s, "TRUNCATE TABLE add_map")
s = append(s, "TRUNCATE TABLE album")
s = append(s, "TRUNCATE TABLE album_permission")
s = append(s, "TRUNCATE TABLE album_view")
s = append(s, "TRUNCATE TABLE album_watch")
s = append(s, "TRUNCATE TABLE media")
s = append(s, "TRUNCATE TABLE media_user_view")
s = append(s, "TRUNCATE TABLE media_view")
s = append(s, "TRUNCATE TABLE media_watch")
s = append(s, "TRUNCATE TABLE private_map")
s = append(s, "TRUNCATE TABLE attachment")
s = append(s, "TRUNCATE TABLE attachment_data")
// 获取新的事务。请参阅 http://golang.org/pkg/database/sql/#DB.Begin
txn, err := myDb.Begin()
if err != nil {
return err
}
defer func() {
// 在函数返回后回滚事务。
// 如果事务已经提交,这将不起作用。
_ = txn.Rollback()
}()
for _, q := range s {
// 在事务中执行查询。
_, err := txn.Exec(q)
if err != nil {
return err
}
}
// 提交事务。
return txn.Commit()
}
英文:
Use a Transaction, like this (see the comments in the code):
func TruncateGalleryImport() error {
s := make([]string, 0)
s = append(s, "TRUNCATE TABLE add_map")
s = append(s, "TRUNCATE TABLE album")
s = append(s, "TRUNCATE TABLE album_permission")
s = append(s, "TRUNCATE TABLE album_view")
s = append(s, "TRUNCATE TABLE album_watch")
s = append(s, "TRUNCATE TABLE media")
s = append(s, "TRUNCATE TABLE media_user_view")
s = append(s, "TRUNCATE TABLE media_view")
s = append(s, "TRUNCATE TABLE media_watch")
s = append(s, "TRUNCATE TABLE private_map")
s = append(s, "TRUNCATE TABLE attachment")
s = append(s, "TRUNCATE TABLE attachment_data")
// Get new Transaction. See http://golang.org/pkg/database/sql/#DB.Begin
txn, err := myDb.Begin()
if err != nil {
return err
}
defer func() {
// Rollback the transaction after the function returns.
// If the transaction was already commited, this will do nothing.
_ = txn.Rollback()
}()
for _, q := range s {
// Execute the query in the transaction.
_, err := txn.Exec(q)
if err != nil {
return err
}
}
// Commit the transaction.
return txn.Commit()
}
答案2
得分: 3
你可以使用一个封装函数来处理提交/回滚逻辑,甚至可以使用字符串匹配来扩展错误处理。
// RDBTransaction 是一个将 SQL 事务抽象为带有隔离级别(isolvl)参数的函数。
// 以下整数表示可用的隔离级别(isolvl):
// 1: SERIALIZABLE
// 2: REPEATABLE READ
// 3: READ COMMITTED
// 4: READ UNCOMMITTED
func RDBTransaction(db *sql.DB, isolvl int, fn func(*sql.Tx) error) (err error) {
var tx *sql.Tx
tx, err = db.Begin()
if err != nil {
return err
}
// 设置事务隔离级别
switch isolvl {
case 1:
_, err = tx.Exec(`set transaction isolation level serializable`)
case 2:
_, err = tx.Exec(`set transaction isolation level repeatable read`)
case 3:
_, err = tx.Exec(`set transaction isolation level read committed`)
case 4:
_, err = tx.Exec(`set transaction isolation level read uncommitted`)
default:
_, err = tx.Exec(`set transaction isolation level serializable`)
}
if err != nil {
return err
}
// 捕获所有错误,进行提交/回滚
defer func() {
if err != nil {
tx.Rollback()
return
}
err = tx.Commit()
}()
// 执行事务
err = fn(tx)
return err
}
这是一个用于处理 SQL 事务的封装函数,它接受一个数据库连接对象 db
、一个隔离级别参数 isolvl
和一个函数 fn
,该函数接受一个 *sql.Tx
对象并返回一个错误。函数内部会根据隔离级别设置事务的隔离级别,并在执行事务过程中进行错误处理和提交/回滚操作。
英文:
You can use a wrapped function to do the commit/rollback logic, possibly even expand the error handling using string matching.
// RDBTransaction is a function which abstracts a sql transaction
// into a function with an isolation level (isolvl) parameter.
// the following integers represent the available isolation levels (isolvl)
// 1: SERIALIZABLE
// 2: REPEATABLE READ
// 3: READ COMMITTED
// 4: READ UNCOMMITTED
func RDBTransaction(db *sql.DB, isolvl int, fn func(*sql.Tx) error) (err error) {
var tx *sql.Tx
tx, err = db.Begin()
if err != nil {
return err
}
// transaction isolation level setting
switch isolvl {
case 1:
_, err = tx.Exec(`set transaction isolation level serializable`)
case 2:
_, err = tx.Exec(`set transaction isolation level repeatable read`)
case 3:
_, err = tx.Exec(`set transaction isolation level read committed`)
case 4:
_, err = tx.Exec(`set transaction isolation level read uncommitted`)
default:
_, err = tx.Exec(`set transaction isolation level serializable`)
}
if err != nil {
return err
}
// catch all, commit/rollback
defer func() {
if err != nil {
tx.Rollback()
return
}
err = tx.Commit()
}()
// run transaction
err = fn(tx)
return err
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论