sql - 有什么简单的方法可以在事务进行到一半时提交工作,然后继续

标签 sql database postgresql go transactions

背景

我正在使用带有 Postgres 数据库的 github.com/jmoiron/sqlx golang 包。

我有以下包装函数来在事务中运行 SQL 代码:

func (s *postgresStore) runInTransaction(ctx context.Context, fn func(*sqlx.Tx) error) error {
    tx, err := s.db.Beginx()
    if err != nil {
        return err
    }
    defer func() {
        if err != nil {
            tx.Rollback()
            return
        }
        err = tx.Commit()
    }()
    err = fn(tx)
    return err
}

鉴于此,请考虑以下代码:

func (s *store) SampleFunc(ctx context.Context) error {
    err := s.runInTransaction(ctx,func(tx *sqlx.Tx) error {

        // Point A: Do some database work

        if err := tx.Commit(); err != nil {
            return err
        }

        // Point B: Do some more database work, which may return an error
    })
}

期望的行为

  • 如果在 A 点有错误,那么交易应该完成零工作
  • 如果B点有错误,那么事务应该还是完成了A点的工作。

当前代码有问题

代码目前没有按预期工作,因为我提交了两次事务(一次在 runInTransaction 中,一次在 SampleFunc 中)。

一个可能的解决方案

在我提交交易的地方,我可以运行类似tx.Exec("SAVEPOINT my_savepoint")的东西,然后defer tx.Exec("ROLLBACK TO SAVEPOINT my_savepoint")

在 B 点的代码之后,我可以运行:tx.Exec("RELEASE SAVEPOINT my_savepoint")

因此,如果 B 点的代码运行没有错误,我将无法ROLLBACK 到我的保存点。

可能解决的问题

我不确定使用保存点是否会扰乱 database/sql 包的行为。此外,我的解决方案似乎有点困惑——肯定有更简洁的方法来做到这一点!

最佳答案

多笔交易

您可以将您的工作分成两个事务:

func (s *store) SampleFunc(ctx context.Context) error {
    err := s.runInTransaction(ctx,func(tx *sqlx.Tx) error {
        // Point A: Do some database work
    })
    if err != nil {
        return err
    }
    return s.runInTransaction(ctx,func(tx *sqlx.Tx) error {
        // Point B: Do some more database work, which may return an error
    })
}

关于sql - 有什么简单的方法可以在事务进行到一半时提交工作,然后继续,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44858531/

相关文章:

sql - 数据库具有完全相同的记录行..为什么会这样?

使用 Play Framework 在 Heroku 中访问数据库时间

SQL查询麻烦

postgresql - 我怎样才能找到 shp2pgsql?

sql - 当条件为 <> true 时,为什么 PostgreSQL 不返回空值

Mysql 查询具有多个子查询,并按不同条件进行分组

mysql 字符串分割

c# - C# 中的 SQL - 为什么这么冗长?

java - 使用hibernate将 map 插入数据库

java - DSL 选择中的 JOOQ 和 PostgreSQL 类型