
僕はgolang+mysqlを使っているのですが、いかんせんトランザクション管理に困っております。
go-sql-driver/mysqlにはbegin、commit、rollbackというメソッドがありますが
まさか一つ一つ手で書く・・・?
力技としてならそれもありかも・・・なんて思っていた時期がありました。
そしてトランザクション管理について調べていると、海外の方が良さげなラッパー関数を紹介してくれていました。
ラッパー関数
元記事はこちら↓
記事で紹介されているラッパー関数は下記になります。
func Transact(db *sql.DB, txFunc func(*sql.Tx) error) (err error) {
tx, err := db.Begin()
if err != nil {
return
}
defer func() {
if p := recover(); p != nil {
tx.Rollback()
panic(p) // re-throw panic after Rollback
} else if err != nil {
tx.Rollback()
} else {
err = tx.Commit()
}
}()
err = txFunc(tx)
return err
}
これはすごい良いんじゃないでしょうか。
実際の処理は移譲していて、このラッパー関数の中ではbeginでトランザクションを開始して
そのトランザクションを移譲する関数の引数に入れています。
そしてdeferの中ではエラーがあればRollback、無事に処理が終わればCommitしています。
実際にラッパー関数を使用するときは
func (s Service) DoSomething() error {
return Transact(s.db, func (tx *sql.Tx) error {
if _, err := tx.Exec(...); err != nil {
return err
}
if _, err := tx.Exec(...); err != nil {
return err
}
})
}
上記のように、ラッパー関数の中に処理を書くことで使用できます。
この方法ならトランザクションをはりたい処理はラッパー関数の中に全部書くことができますね。
僕の中で現状のベストプラクティスになりそうです。
まとめ
golangでのトランザクション管理ってみんなどうしているんでしょうか。。
もしもgolangでゲームなどを作る場合はトランザクション管理が必須だし。。
でもその割には検索しても有力な知見も出てこない感じがするし。。
おわり!!