I've seen a few questions on Go's defer
, but nothing like the implementation I'm trying to do yet.
The test case
The application I'm writing does a fair bit of db transactions, so I have a function
func getCursor() *sql.Tx {
psqlInfo := fmt.Sprintf("host=%s port=%d user=%s "+
"password=%s dbname=%s sslmode=disable",
host, port, user, password, dbname)
db, err := sql.Open("postgres", psqlInfo)
if err != nil {
panic(err)
}
defer db.Close()
err = db.Ping()
if err != nil {
panic(err)
}
tx, err := db.Begin()
handleErr(err, tx)
return tx
}
Which gives me back a transaction, and defer
's db.Close()
so I don't flood the database's pool.
Other functions that use this are:
// addPerson lets you add a person using a transaction that's passed as the first argument.
func addPerson(tx *sql.Tx, firstName string, lastName string, phoneNumber string) sql.Result {
statement := "INSERT INTO public.persons (first_name, last_name, phone_number, data) VALUES ($1, $2, $3, '{}')"
res, err := tx.Exec(statement, firstName, lastName, phoneNumber)
handleErr(err, tx)
return res
}
// wraps addPerson in a transaction to be used as standalong
func AddPerson(firstName string, lastName string, phoneNumber string) int64 {
tx := getCursor()
defer tx.Rollback()
err := tx.Commit()
res := addPerson(tx, firstName, lastName, phoneNumber)
handleErr(err, tx)
affected, err := res.RowsAffected()
handleErr(err, tx)
return affected
}
from https://blog.golang.org/defer-panic-and-recover
- Deferred function calls are executed in Last In First Out order after the surrounding function returns.
So if the tx.Commit()
fails, the transaction will be rolled back.
My confusion is around the defer db.Close()
. If this is getting executed after getCursor
is done, how am I still able to make an INSERT
into the database? (The code in the question works, I'm just really confused by why it does). Any help clarifying is super appreciated.