Transactions & Connections

Connection lifecycle, ConnectionManager, the transaction {} function, nested savepoints, deferred side effects, and how GraphQL requests manage connections.

ConnectionManager

ConnectionManager is the per-request handle to a database connection. It is lazy — no physical connection is obtained from the pool until the first SQL operation.

It lives in the coroutine context. Repository methods, transaction {}, and RequestCache all access it automatically.

The transaction {} Function

kotlin

Wraps a block in a database transaction. If the block completes normally, it commits. If it throws, it rolls back and the exception propagates.

kotlin
Begin, commit, and rollback run in NonCancellable context — coroutine cancellation cannot leave a transaction half-open.

Nested Transactions via Savepoints

Calling transaction {} inside another transaction {} creates a SQL SAVEPOINT:

  • Inner commit releases the savepoint (does not commit to the database).
  • Inner rollback rolls back to the savepoint (outer transaction continues).
  • Only the outermost commit actually calls connection.commit().
kotlin

GraphQL Connection Management

GraphQL requests work differently from HTTP routes:

  • Each field resolver gets its own ConnectionManager — no shared transaction across fields.
  • Connections are acquired lazily per field — fields that don't touch the database never acquire a connection.
  • A ConnectionLimiter semaphore (default limit 5) prevents a single GraphQL request from holding too many concurrent connections.

Deferred Side Effects

Several systems register callbacks to defer side effects until after the transaction commits:

  1. Remote cache writesRequestCache flushes pending puts/removes on onCommit(). Rolled-back writes are discarded.
  2. Job queue enqueuesdispatch() defers via dbRunAfterCommit. Background jobs don't start before data is visible.
  3. Pub-sub publishing — subscribers don't receive notifications about uncommitted data.

Background Jobs

For code outside a request context, use withConnectionManager:

kotlin