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.

Problem
Section titled “Problem”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.
When to use it
Section titled “When to use it”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.
Coordinates
Section titled “Coordinates”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}Core concepts
Section titled “Core concepts”JdbcRepositoryexecutes in the currenttransaction {}; it does not open a transaction.ResultRow.toEntity()should create a detached record before leaving the transaction.findPageruns count and content queries separately. Snapshot consistency depends on the surrounding transaction and isolation.AuditableJdbcRepositoryandSoftDeletedJdbcRepositorymake update semantics explicit.newSuspendedTransactionsupport in 1.11 is experimental and remains a blocking JDBC path.
Quick start
Section titled “Quick start”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.
API by task
Section titled “API by task”| Task | Stable API |
|---|---|
| Read/existence | findById, findByIdOrNull, findAll, findFirstOrNull, existsById |
| Page | findPage |
| Write | saveAll, updateById, updateAll, deleteById, batch insert/upsert |
| Audit | auditedUpdateById, auditedUpdateAll |
| Soft delete | softDeleteById, restoreById, findActive, findDeleted |
| SQL/schema | CteQuery, SchemaUtilsExtensions, TableExtensions |
| Blocking coroutine bridge | newSuspendedTransaction/virtual-thread helper, with explicit dispatcher ownership |
Recommended patterns
Section titled “Recommended patterns”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.
Integrations
Section titled “Integrations”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.
Configuration
Section titled “Configuration”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.
Failure modes
Section titled “Failure modes”- 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
findPageis one query can expose count/content drift. - Using generic update methods on an auditable table skips audited update fields.
Operations
Section titled “Operations”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.
Testing
Section titled “Testing”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.
Workshops and learning path
Section titled “Workshops and learning path”Start with Transaction ownership, continue to Repository patterns, then Operations and testing. The JDBC/R2DBC guide explains when this path is the better fit.
Limitations
Section titled “Limitations”JDBC remains blocking even when invoked from a suspending function. This library does not provide a driver, pool, automatic transaction, or universal retry policy.
Release diagrams
Section titled “Release diagrams”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
Section titled “JDBC Architecture Overview diagram”Release README: exposed/jdbc/README.md
Repository Contract Map diagram
Section titled “Repository Contract Map diagram”Release README: exposed/jdbc/README.md
VirtualThread transaction helper diagram
Section titled “VirtualThread transaction helper diagram”Release README: exposed/jdbc/README.md
findById — Single record lookup diagram
Section titled “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”Release README: exposed/jdbc/README.md
softDeleteById / restoreById — Soft delete and restore diagram
Section titled “softDeleteById / restoreById — Soft delete and restore diagram”Release README: exposed/jdbc/README.md





