问题描述
我在我的一个 Golang 应用程序中有一个用例来更新 API 中的多个表,如果其中一个更新失败,我希望所有以前的更新回滚(Java 中的 @Transactional 所做的事情)。 我尝试按以下方式进行:
func (d *dao) Method1(opt string) error {
tx,err := d.DB.BeginTx(context.Background(),nil)
if err != nil {
return errors.Errorf("Unable to start transaction")
}
err := d.dao1.Update1(opt)
if err != nil {
log.Infof("Error : %s. Rolling back transaction",err)
_ = tx.Rollback()
log.Infof("Transaction rolled back while update 1")
return err
}
err = d.dao2.Update2(opt)
if err != nil {
log.Errorf("Error in making update 2 "+
"Error %v ",err)
_ = tx.Rollback()
log.Infof("Transaction rolled back while update 2")
return err
}
}
}
func(d *dao1) Update1 error {
var query = "update T1 set C1 = ? where id = ?"
_,err := d.DB.Exec(query,"v1","v2")
return err
}
func(d *dao2) Update2 error {
var query = "update T2 set C2 = ? where id = ?"
_,"v2")
return err
}
但这不起作用,因为我们在 Update1 和 Update2 方法中创建了一个新事务。 所以我尝试在方法 Update1 和 Update2 的方法参数中传递事务,如下所示:
func Update1(tx sql.Tx) error {
var query = "update T1 set C1 = ? where id = ?"
_,err := tx.Exec(query,"v2")
return err
}
但问题是在某些用例中,我只想调用方法 Update1。那么,Update1 方法中要传递的事务的值应该是多少?
或者有更好的方法来做到这一点。有人可以帮忙吗?
解决方法
如果我理解正确,在某些情况下,您希望调用 Update1
而不是 Update2
,而在其他情况下,您希望两个更新都发生。如果是这样,那么我建议这更多是一个设计问题,而不是 Tx
的使用。我认为设计两个函数,每个函数都描述您期望的行为,并将关于调用哪个函数的逻辑委托给调用者,可能会奏效。类似的东西:
func Caller() error {
if condition {
return UpdateOne()
}
return UpdateBoth()
}
func UpdateOne() error { … }
func UpdateBoth() error { … }