Transactions Go Basics
Fast recall
Quick revision
Core answer
Whether you understand Transactions Go Basics beyond memorized syntax.
Giving a definition without explaining a practical trade-off.
Connect the concept to a small production example and state its complexity or failure mode.
Interview-ready guide
Interview answer
The pattern, executed:
tx, err := db.Begin()
if err != nil { return err }
defer tx.Rollback() // SAFE: no-op if Commit already succeeded
_, err = tx.Exec("INSERT INTO users (name, email) VALUES (?, ?)", "Cy", "cy@x.com")
if err != nil {
return err // rollback happens via defer — the insert is undone
}
_, err = tx.Exec("UPDATE counters SET n = n + 1 WHERE key = 'users'")
if err != nil {
return err // same — everything undone
}
return tx.Commit() // both operations atomically visibleVerified: after Commit — both changes present. After Rollback — neither.
The defer-Rollback idiom: tx.Rollback returns an error if the transaction is already committed — the deferred call's error is ignored (it's the safety net, not the primary path). The pattern:
defer func() {
if rerr := tx.Rollback(); rerr != nil && rerr != sql.ErrTxDone {
log.Printf("rollback: %v", rerr) // unexpected
}
}()The isolation (what a transaction guarantees): ACID — Atomic (all or nothing), Consistent (constraints hold), Isolated (concurrent transactions don't see partial state), Durable (committed = survives crash). The isolation levels (read committed, repeatable read, serializable) tune the concurrency trade.
The nesting story: database/sql has NO nested transactions — tx on tx is a driver question (savepoints are the SQL-level emulation). The common pattern: one transaction per business operation.
Transactions Go Basics
Direct Answer
tx, err := db.Begin() — tx.Exec/Query for the transaction's operations — tx.Commit() or tx.Rollback(). Always defer rollback (the idempotent safety). The transaction is all-or-nothing.
Deep Dive & Architecture
The connection binding, the mechanism interviewers probe: a tx holds ONE connection from the pool for its entire life — the transaction's operations MUST go through tx (not db — db might route to a different connection, silently escaping the transaction). The classic bug: calling db.Exec inside a transaction block — the operation runs on a different connection, outside the transaction, not rolled back.
The context form (the modern discipline): tx, err := db.BeginTx(ctx, nil) — the context cancels, the transaction aborts. Request-scoped transactions: the handler's context carries through Begin, all Execs, and Commit — a client disconnect mid-transaction rolls it back, saving the DB from orphaned work.
The IsolationLevel tuning: the options parameter of BeginTx sets the level (sql.LevelSerializable for the strongest isolation, at concurrency cost). The default (each driver's default, usually read-committed) is right for most services; the higher levels are the banking/inventory trade.
Common Mistakes & Pitfalls
Giving a definition without explaining a practical trade-off.
Check your understanding
Answer these without looking back at the article.
- When would you use Transactions Go Basics in a real project?
- How would you compare Transactions Go Basics with an alternative?
- What is a common mistake when using Transactions Go Basics?
Looking for a structured roadmap?
Every module on this page is also part of the full Java backend interview track.