Sobes.tech
Middle — Middle+

Como gerir transações dentro de um único método, quando se utilizam várias operações transacionais, tendo em conta o contexto de execução?

sobes.tech IA

Resposta da IA

Em Go, para gerir transações dentro de um mesmo método com várias operações transacionais, geralmente usa-se um objeto de transação obtido do contexto da base de dados (por exemplo, *sql.Tx). É importante passar esse objeto para cada função que realiza operações com a base de dados, para que todas façam parte de uma mesma transação.

Exemplo:

func doComplexOperation(db *sql.DB) error {
    tx, err := db.Begin()
    if err != nil {
        return err
    }
    defer func() {
        if p := recover(); p != nil {
            tx.Rollback()
            panic(p)
        } else if err != nil {
            tx.Rollback()
        } else {
            err = tx.Commit()
        }
    }()

    err = operation1(tx)
    if err != nil {
        return err
    }

    err = operation2(tx)
    if err != nil {
        return err
    }

    return nil
}

func operation1(tx *sql.Tx) error {
    // Execução de queries SQL usando tx.Exec ou tx.Query
    return nil
}

func operation2(tx *sql.Tx) error {
    // Similar
    return nil
}

Dessa forma, todas as operações são realizadas dentro de uma mesma transação, e em caso de erro, ocorre um rollback. O contexto de execução (context.Context) pode ser usado para cancelar ou definir um timeout, passando-o aos métodos de consulta, mas o objeto de transação deve ser passado explicitamente.