Skip to content
Exposed docs1.11

Exposed R2DBC Library

Latest stable Based on Exposed release 1.11.0

Suspending and Flow-based persistence helpers for an end-to-end R2DBC path. The caller or framework owns suspendTransaction and connection context.

Transaction ownership

R2DBC changes more than method signatures: driver access, connection ownership, transaction propagation, cancellation, result collection, Spring integration, and testing all need a non-blocking contract. This module provides repository and DSL helpers while leaving the transaction boundary visible.

Choose R2DBC when the driver, framework, transaction manager, and complete request path are non-blocking and the workload benefits from concurrency without dedicating one platform thread per waiting database call. Do not choose it on the assumption that it is automatically faster; latency and throughput depend on the driver, database, pool, query shape, and workload.

dependencies {
implementation(platform("io.github.bluetape4k:bluetape4k-dependencies:<version>"))
implementation("io.github.bluetape4k.exposed:bluetape4k-exposed-r2dbc")
runtimeOnly("org.postgresql:r2dbc-postgresql") // select the deployed driver
}
  • R2dbcRepository runs in the current suspendTransaction; it does not open one.
  • Single-value operations suspend; multi-row reads return cold Flow values.
  • Collect a repository Flow inside the transaction that owns its connection.
  • Cancellation can abort collection, but the driver/database determine how promptly server work stops and resources are released.
  • findPage performs count and content work separately within the caller’s transaction.
suspendTransaction(db = database) {
val actors = repository.findAll(limit = 20).toList()
val page = repository.findPage(pageNumber = 0, pageSize = 20)
}

Keep creation and terminal collection of database-backed flows inside the same transaction boundary.

TaskStable API
Single read/writesuspending findById, saveAll, updateById, deleteById
Multi-row readfindAll, findBy, findAllByIds returning Flow
Pagesuspending findPage
AuditauditedUpdateById, auditedUpdateAll
Soft deletesuspending writes plus findActive/findDeleted flows
Query helpersCteQuery, QueryExtensions, ReadableExtensions, table helpers
Conflict handlingR2DBC batch insert-on-conflict helpers

Define one coroutine transaction around one business operation. Do not let a repository open an isolated transaction, because several writes then cannot share rollback. Collect database flows before the boundary closes, convert rows to detached values, and keep blocking libraries off the R2DBC call chain.

Spring R2DBC integration can provide transaction context through the framework module. R2DBC cache variants preserve suspending boundaries but introduce their own client lifecycle and failure semantics. Database adapters must explicitly support the selected R2DBC behavior.

Configure the R2DBC ConnectionFactory, pool, driver options, timeouts, and Exposed R2dbcDatabase in the application/framework layer. Size the pool from measured database capacity, not coroutine count.

  • Collecting a cold database Flow after suspendTransaction closes loses its transaction/connection context.
  • Inserting a blocking codec, cache client, or JDBC call into the path blocks coroutine threads.
  • Treating cancellation as guaranteed server-side query termination overstates the contract.
  • Mixing Spring and manually opened transaction contexts can split one use case across connections.
  • Migrating syntax without replacing the driver and tests leaves a half-blocking system.

Observe pool acquisition, active connections, transaction/query duration, cancellation, timeout, and error signals. Bound result streams, and confirm driver resource cleanup under cancellation and partial consumption.

Use bluetape4k-exposed-r2dbc-tests with R2DBC drivers and Testcontainers. Test cancellation, rollback, collection within the boundary, pool exhaustion, dialect behavior, and cleanup after failures. A JDBC-only test does not prove the R2DBC path.

Read Coroutine transactions, Repository patterns, and Cancellation and testing. The JDBC/R2DBC guide includes migration cost and operational trade-offs.

R2DBC is not an automatic performance upgrade and does not make blocking dependencies non-blocking. The library supplies no driver, universal cancellation guarantee, or implicit transaction.

These diagrams are loaded directly from README assets published with the 1.11.0 release and pinned to its immutable commit. They describe this manual’s released structure and runtime flows, not later Snapshot changes. Select a preview to open the SVG at the same release commit.

Core R2DBC repository structure diagram

Release README: exposed/r2dbc/README.md

R2DBC repository capability map

Release README: exposed/r2dbc/README.md

R2DBC suspend transaction sequence diagram

Section titled “R2DBC suspend transaction sequence diagram”

R2DBC suspend transaction sequence diagram

Release README: exposed/r2dbc/README.md

R2DBC soft-delete visibility flow diagram

Release README: exposed/r2dbc/README.md