Skip to content
Exposed docs1.11

Exposed JDBC Library

Latest stable Based on Exposed release 1.11.0

Blocking JDBC persistence helpers and repository contracts. The caller or framework owns the transaction and connection boundary.

JDBC or R2DBC decision

An application using Exposed JDBC still needs consistent record mapping, CRUD, paging, batch operations, audit updates, soft delete, schema helpers, CTE support, and coroutine isolation for blocking work. This module supplies those conventions without hiding Exposed’s JDBC transaction model.

Choose JDBC when the database driver, connection pool, framework transaction manager, and application call path are blocking. It is the straightforward production path for Spring JDBC transactions and existing JDBC observability/tooling. A coroutine-based service can still use JDBC if blocking work is isolated on a suitable dispatcher or virtual thread.

dependencies {
implementation(platform("io.github.bluetape4k:bluetape4k-dependencies:<version>"))
implementation("io.github.bluetape4k.exposed:bluetape4k-exposed-jdbc")
runtimeOnly("org.postgresql:postgresql") // choose the deployed driver
}
  • JdbcRepository executes in the current transaction {}; it does not open a transaction.
  • ResultRow.toEntity() should create a detached record before leaving the transaction.
  • findPage runs count and content queries separately. Snapshot consistency depends on the surrounding transaction and isolation.
  • AuditableJdbcRepository and SoftDeletedJdbcRepository make update semantics explicit.
  • newSuspendedTransaction support in 1.11 is experimental and remains a blocking JDBC path.
transaction(database) {
val actor = repository.findByIdOrNull(42L)
val page = repository.findPage(pageNumber = 0, pageSize = 20)
}

Open the transaction at the service/framework boundary, perform every repository operation inside it, and return detached values.

TaskStable API
Read/existencefindById, findByIdOrNull, findAll, findFirstOrNull, existsById
PagefindPage
WritesaveAll, updateById, updateAll, deleteById, batch insert/upsert
AuditauditedUpdateById, auditedUpdateAll
Soft deletesoftDeleteById, restoreById, findActive, findDeleted
SQL/schemaCteQuery, SchemaUtilsExtensions, TableExtensions
Blocking coroutine bridgenewSuspendedTransaction/virtual-thread helper, with explicit dispatcher ownership

Put one business use case inside one transaction boundary. Keep repository methods transaction-neutral so several calls can commit or roll back together. Convert DAO entities and rows to records inside the boundary. For pages that require a stable count/content view, select an isolation level that supplies it or redesign the query.

Spring transaction management can own the boundary through the Spring JDBC module. Cache modules wrap repository results but do not replace transaction rules. Database adapters refine dialect behavior. JDBC test support supplies database fixtures.

Configure the DataSource, pool limits/timeouts, driver properties, isolation, and Exposed Database in the application or framework module. Match pool size to blocking concurrency; coroutine count is not a safe pool-size estimate.

  • Calling a repository outside transaction {} fails because no JDBC transaction context exists.
  • Returning a DAO entity and reading lazy state later crosses the closed boundary.
  • Running JDBC on a constrained coroutine event-loop thread blocks unrelated work.
  • Assuming findPage is one query can expose count/content drift.
  • Using generic update methods on an auditable table skips audited update fields.

Measure pool wait, query duration, transaction duration, timeout/rollback counts, and slow SQL. Attach request/job identity before audited writes. Size batch operations from actual driver and database limits.

Use bluetape4k-exposed-jdbc-tests and Testcontainers for the deployed dialect. Test commit, rollback, isolation-sensitive behavior, batch edge cases, audit fields, soft delete, and mapper behavior. Keep database cleanup deterministic.

Start with Transaction ownership, continue to Repository patterns, then Operations and testing. The JDBC/R2DBC guide explains when this path is the better fit.

JDBC remains blocking even when invoked from a suspending function. This library does not provide a driver, pool, automatic transaction, or universal retry policy.

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.

JDBC Architecture Overview diagram

Release README: exposed/jdbc/README.md

Repository Contract Map diagram

Release README: exposed/jdbc/README.md

VirtualThread transaction helper diagram

Release README: exposed/jdbc/README.md

findById — Single record lookup diagram

Release README: exposed/jdbc/README.md

save + findPage — Save then paginate diagram

Section titled “save + findPage — Save then paginate diagram”

save + findPage — Save then paginate diagram

Release README: exposed/jdbc/README.md

softDeleteById / restoreById — Soft delete and restore diagram

Section titled “softDeleteById / restoreById — Soft delete and restore diagram”

softDeleteById / restoreById — Soft delete and restore diagram

Release README: exposed/jdbc/README.md