Golang Database
Priority: P0 (CRITICAL)
Rules
- Prefer explicit SQL or generated query layers when performance and shape matter.
- Configure the pool; defaults are rarely enough for real traffic.
- Pass
context.Contextto every query path. - Keep transaction ownership at the service/use-case boundary, not split across handlers.
Recipe
- Choose the access layer:
database/sql,pgx,sqlc, or ORM only if the team already standardizes on it. - Tune the pool: max open, max idle, connection lifetime, and idle lifetime.
- Hide storage details behind repository methods or query services.
- Close rows and inspect
rows.Err(). - Wrap multi-step writes in one transaction and propagate context/deadlines.
Verify
- [ ] Query methods accept
context.Context. - [ ] Pool settings are explicit.
- [ ] Rows are closed and iteration errors checked.
- [ ] Transaction scope matches one business action.
- [ ] Retry/idempotency policy is clear for contested writes.
Anti-Patterns
- No global db var: inject DB connection via constructor.
- No context-less queries: use
QueryContext/ExecContext; bare queries ignore timeouts. - No leaked rows: always
defer rows.Close()and checkrows.Err(). - No transaction split-brain: handler, repo, and service cannot each open their own transaction for one unit of work.