问题描述
func (r *repoPG) WithTransaction(txFunc func() error) (err error) {
tx := db.NewTx()
defer func() {
if r := recover(); r != nil {
err = fmt.Errorf("panic: %v",r)
tx.Rollback()
} else if err != nil {
tx.Rollback()
} else {
tx.Commit()
}
}()
err = txFunc()
return
}
我想每次都写那么长的defer
,所以我想写这样的func:
func TxDefer(tx,err) {
if r := recover(); r != nil {
err = fmt.Errorf("panic: %v",r)
tx.Rollback()
} else if err != nil {
tx.Rollback()
} else {
tx.Commit()
}
}
使用方式如下:
func (r *repoPG) WithTransaction(txFunc func() error) (err error) {
tx := db.NewTx()
defer TxDefer(tx,err)
err = txFunc()
return
}
但这很不正确,因为err
始终是原始的,而不是txFunc()
的结果,对吧?
我该如何解决?
解决方法
将错误的地址传递给函数。这使函数可以访问调用者变量的当前值。它还允许函数设置变量。
回滚和提交返回错误。这些错误应返回给调用者。
func TxDefer(tx Transaction,perr *error) {
if r := recover(); r != nil {
*perr = fmt.Errorf("panic: %v",r)
tx.Rollback()
} else if *perr != nil {
err = tx.Rollback()
if err != nil {
// replace original error with rollback error
*perr = err
}
} else {
*perr = tx.Commit()
}
}
像这样使用它:
func (r *repoPG) WithTransaction(txFunc func() error) (err error) {
tx := db.NewTx()
defer TxDefer(tx,&err)
err = txFunc()
return
}
在上面的代码中,表达式*perr
等于err
中WithTransaction
的当前值。问题中的err
的值是延期时err
的值。