【问题标题】:Do I need to explicitly rollback a transaction?我需要显式回滚事务吗?
【发布时间】:2022-01-19 05:22:58
【问题描述】:

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

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...
}

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

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

顺便说一句,我正在使用 SQLite,如果有任何答案是特定于 db 的,我也想知道 MySQL 的行为。

【问题讨论】:

    标签: database go


    【解决方案1】:

    默认情况下,任何数据库错误都会自动取消并回滚事务。这就是交易的用途。所以严格来说,在出现数据库错误(即外键违规什么的)的情况下,不需要自己回滚事务。

    但是,您应该始终在创建事务后立即推迟回滚。这样,如果有任何错误与数据库无关,事务将回滚并清理。在这种情况下,回滚已经中止的事务将是无操作的,因此无害。

    这在代码中看起来是这样的:

    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】:

      如果在执行任何查询时出现错误,则回滚 tx 很重要,否则它仍在运行并持有锁。查看this 帖子。

      【讨论】:

      • 我知道这一点。我要问的实际上是 Go 问题,而不是 DB 问题。即我想知道如果没有执行提交,tx 是否会在函数“自动”退出时回滚。 :-)
      • 客户端断开连接或事务被垃圾回收后,未提交的事务会自动回滚。更多信息stackoverflow.com/a/23502629/10984192.
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-01-01
      • 2014-08-21
      • 1970-01-01
      • 2012-04-05
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多