0

I have a use case in one of my Golang applications to update multiple tables in an API and in case one of the updates fails, I would want all the previous updates to roll back (Something that @Transactional in Java does). I tried doing it in the below way:

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 = ?"
        _, err := d.DB.Exec(query, "v1", "v2")
        return err
}

But this doesn't work as we are creating a new transaction in the Update1 & Update2 methods. So I tried to pass transactions in the method parameters of method Update1 & Update2 like below:

func Update1(tx sql.Tx) error {
    var query = "update T1 set C1 = ? where id = ?"
    _, err := tx.Exec(query, "v1", "v2")
    return err
}

But the problem is in some use cases I want just method Update1 to be called. In that case, what should be the value of the transaction to be passed in the Update1 method?

Or is there a better way to do it. Can someone please help?

1 Answer 1

0

If I understand correctly, in some cases you want Update1 to be called but not Update2, while in other cases you want both updates to happen. If that’s the case, then I would suggest that this is more of a design problem, rather than with the usage of Tx. I think designing two functions that each describes the behavior you expect, and delegating the logic about which one to call to the caller, might work. Something like:

func Caller() error {
    if condition {
        return UpdateOne()
    }
    return UpdateBoth()
}

func UpdateOne() error { … }
func UpdateBoth() error { … }
Sign up to request clarification or add additional context in comments.

1 Comment

Still in the Caller() method above, how will I make sure that both the methods are called in the same tx ?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.