Idiomatic way to do multiple queries in golang in one transaction

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

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
}

huangapple
  • 本文由 发表于 2015年1月2日 19:09:53
  • 转载请务必保留本文链接:https://go.coder-hub.com/27741185.html
匿名

发表评论

匿名网友

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

确定