douzuizhuo0587 2017-07-01 07:36 采纳率: 0%
浏览 423
已采纳

在事务中途提交工作,然后继续执行的一种简单方法是

Background

I am using the github.com/jmoiron/sqlx golang package with a Postgres database.

I have the following wrapper function to run SQL code in a transaction:

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
}

Given this, consider the following code:

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

Desired behavior

  • If there is an error at Point A, then the transaction should have done zero work
  • If there is an error at Point B, then the transaction should still have completed the work at Point A.

Problem with current code

The code does not work as intended at the moment, because I am committing the transaction twice (once in runInTransaction, once in SampleFunc).

A Possible Solution

Where I commit the transaction, I could instead run something like tx.Exec("SAVEPOINT my_savepoint"), then defer tx.Exec("ROLLBACK TO SAVEPOINT my_savepoint")

After the code at Point B, I could run: tx.Exec("RELEASE SAVEPOINT my_savepoint")

So, if the code at Point B runs without error, I will fail to ROLLBACK to my savepoint.

Problems with Possible Solution

I'm not sure if using savepoints will mess with the database/sql package's behavior. Also, my solution seems a bit messy -- surely there is a cleaner way to do this!

  • 写回答

2条回答 默认 最新

  • duanjiu2701 2017-07-02 06:52
    关注

    I had the problem alike: I had a lots of steps in one transaction. After starting transaction:

    • BEGIN
    • In loop:

      • SAVEPOINT s1
      • Some actions ....
      • If I get an error: ROLLBACK TO SAVEPOINT s1
      • If OK go to next step
    • Finally COMMIT

    This approach gives me ability to perform all steps one-by-one. If some steps got failed I can throw away only them, keeping others. And finally commit all "good" work.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(1条)

报告相同问题?

悬赏问题

  • ¥15 为什么使用javacv转封装rtsp为rtmp时出现如下问题:[h264 @ 000000004faf7500]no frame?
  • ¥15 乘性高斯噪声在深度学习网络中的应用
  • ¥15 运筹学排序问题中的在线排序
  • ¥15 关于docker部署flink集成hadoop的yarn,请教个问题 flink启动yarn-session.sh连不上hadoop,这个整了好几天一直不行,求帮忙看一下怎么解决
  • ¥30 求一段fortran代码用IVF编译运行的结果
  • ¥15 深度学习根据CNN网络模型,搭建BP模型并训练MNIST数据集
  • ¥15 C++ 头文件/宏冲突问题解决
  • ¥15 用comsol模拟大气湍流通过底部加热(温度不同)的腔体
  • ¥50 安卓adb backup备份子用户应用数据失败
  • ¥20 有人能用聚类分析帮我分析一下文本内容嘛