Do I need to explicitly rollback a transaction?

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

Do I need to explicitly rollback a transaction?

问题

我想知道Go语言如何处理失败的数据库事务。我的代码如下:

func assert(e interface{}) {
    if e != nil {
        panic(e)
    }
}

// 调用者将处理panic
func SomeDBOperation(db *sql.DB) {
    tx, err := db.Begin()
    assert(err)
    defer func() {
        if e := recover(); e != nil {
            tx.Rollback()
            panic(e)
        }
        assert(tx.Commit())
    }()
    // 可能会引发panic的一些代码...
}

我可以像这样简化错误检查吗:

func SomeDBOperation(db *sql.DB) {
    tx, err := db.Begin()
    assert(err)
    defer func() { assert(tx.Commit()) }()
    // 可能会引发panic的一些代码...
}

顺便说一下,我正在使用SQLite,如果有任何与数据库相关的答案,我也想了解在MySQL中的行为。

英文:

I would like to know how Go handles failed DB transaction. My code looks like:

func assert(e interface{}) {
    if e != nil {
        panic(e)
    }
}

//the caller will handle panics
func SomeDBOperation(db *sql.DB) {
    tx, err := db.Begin()
    assert(err)
    defer func() {
        if e := recover(); e != nil {
            tx.Rollback()
            panic(e)
        }
        assert(tx.Commit())
    }()
    // some code that can possibly panic...
}

Can I simplify the error checking like this:

func SomeDBOperation(db *sql.DB) {
    tx, err := db.Begin()
    assert(err)
    defer func() { assert(tx.Commit()) }()
    // some code that can possibly panic...
}

BTW, I am using SQLite, if any answer is db-specific, I would also like to know the behavior with MySQL.

答案1

得分: 4

默认情况下,任何数据库错误都会自动取消并回滚事务。这就是事务的作用。严格来说,在出现数据库错误(例如外键违规或其他错误)的情况下,没有必要自己回滚事务。

然而,你应该在创建事务后立即延迟回滚。这样,如果有任何与数据库无关的错误,事务将被回滚和清理。在这种情况下,回滚已经中止的事务将不会产生任何影响,因此是无害的。

代码中的实现如下所示:

func SomeDBOperation(db *sql.DB) error {
    txn, err := db.Begin()
    if err != nil {
        return fmt.Errorf("failed to start transaction: %w", err)
    }
    defer txn.Rollback() // nolint:errcheck
    /* ... 其他你关心的逻辑和数据库操作 */
    return nil
}
英文:

By default, any database error will automatically cancel and rollback the transaction. That's what transactions are for. So strictly speaking, in the case of a database error (i.e. foreign key violation or something), there's no need to rollback the transaction yourself.

However, you should always defer a rollback immediately after creating the transaction. This is so that if there are any errors not related to the database, that the transaction is rolled back and cleaned up. In such a case, rolling back a transaction that has already been aborted will be a no-op, so harmless.

The way this looks in code is something like this:

func SomeDBOperation(db *sql.DB) error {
    txn, err := db.Begin()
    if err != nil {
        return fmt.Errorf("failed to start transaction: %w", err)
    }
    defer txn.Rollback() // nolint:errcheck
    /* ... whatever other logic and DB operations you care about */
    return nil
}

答案2

得分: -1

如果在执行任何查询时出现错误,回滚事务非常重要,否则事务将继续运行并持有锁。请查看这篇帖子

英文:

It is important to rollback the tx if there is an error while executing any query, otherwise it is still running and holding locks. Check out this post .

huangapple
  • 本文由 发表于 2021年12月16日 11:46:28
  • 转载请务必保留本文链接:https://go.coder-hub.com/70373602.html
匿名

发表评论

匿名网友

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

确定