LoginSignup
2
3

More than 3 years have passed since last update.

GoでDBのトランザクション処理を書いてみた

Posted at

今回は、Goでトランザクション処理を書いてみます。


import (
    "database/sql"
    "log"
)

func withTransaction(ctx context.Context, db *sql.DB, txFunc func(*sql.Tx) error) error {
    tx, err := db.BeginTx(ctx, nil)
    if err != nil {
        log.Println(err.Error())
        return err
    }
    defer func() {
        if p := recover(); p != nil {
            tx.Rollback()
            panic(p) // re-throw panic after Rollback
        } else if err != nil {
            log.Println(err)
            tx.Rollback()
        } else {
            err = tx.Commit()
        }
    }()
    err = txFunc(tx)
    return err
}

第3引数には、第1引数に*sql.Txが入り、error型が返り値の無名関数が入ります。
実際の使われ方をみた方が早いので以下を参考にしてください。
GoのクエリビルダSquirrelを使用しています。

type userRepository struct {
    DBClient *sql.DB
}

func (r *userRepository) CreateUser(ctx context.Context, userID string) error {
    query := sq.Insert(usersTable).
          SetMap(sq.Eq{
             "id":          userID,
          })
    return withTransaction(ctx, r.DBClient, func(tx *sql.Tx) error {
        if _, err := query.RunWith(tx).ExecContext(ctx); err != nil {
            log.Println(err)
            return err
         }
        return nil
      }

txFuncでエラーやpanicが発生したらdefer funcの中でtx.Rollbackが呼ばれ、dbの内容の修正が取り消され、正常終了した場合はtx.Commitがされます。

2
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
3