Introduction
Use the Database.connect() function to connect to your database, adjusting the values of the settings to match your environment.
Transaction context
Exposed R2DBC stores the current transaction in the coroutine context.
However, Ktor route handlers can switch coroutine dispatchers, which may cause the transaction context to be lost if it is not explicitly propagated.
The suspendTransaction() function does not allow you to pass a custom coroutine context as a parameter.
If you need to run a transaction on a specific dispatcher (for example, Dispatchers.IO) or with additional context, wrap the transaction in withContext().
private lateinit var database: R2dbcDatabase
suspend fun <T> transaction(block: suspend () -> T): T = withContext(currentCoroutineContext() + Dispatchers.IO) { inTopLevelSuspendTransaction(database) { block() } }
suspend fun Application.configureDatabase() {
database = R2dbcDatabase.connect( url = "r2dbc:postgresql://${DATABASE_HOST}:5432/${DATABASE_NAME}", driver = "postgresql", user = "postgres", password = DATABASE_PASSWORD )}This snippet declares a top‑level variable database instance that will hold the Exposed R2DBC. It is marked lateinit because it is initialized later in configureDatabase(), after the application starts.
Also, defines a helper function transaction that runs any suspending block inside a database transaction:
-
withContext(currentCoroutineContext() + Dispatchers.IO)starts from the current coroutine context (so it keeps elements like job, MDC, etc.). and addsDispatchers.IOto ensure that the transaction runs on the IO dispatcher, which is appropriate for database operations. -
inTopLevelSuspendTransaction(database) { ... }starts a top‑level suspending transaction using thedatabaseconnection andblock()is the user‑provided code that will run inside the transaction context and onDispatchers.IO.
In practice, you can use this helper like:
val user = transaction { // Suspended Exposed calls here, inside a transaction // e.g. Users.select { Users.id eq id }.singleOrNull() }