Working with Databases
In Exposed, the Database and R2dbcDatabase classes represent a database instance, and encapsulates the necessary connection details and configuration required to interact with a specific database.
Choosing between JDBC and R2DBC
Exposed supports both JDBC and R2DBC as transport layers for database connectivity. Understanding their differences will help you choose the right approach for your application:
JDBC
JDBC (Java Database Connectivity) is the traditional, synchronous and blocking API used for interacting with relational databases. Exposed's JDBC integration is well-established with broad database support and extensive tooling. It’s ideal for:
Traditional applications where simplicity is preferred over scalability.
Projects using connection pools and transaction management in a synchronous context.
JDBC is well-supported and works seamlessly with most existing database drivers and tools.
R2DBC
R2DBC (Reactive Relational Database Connectivity) is a non-blocking, asynchronous alternative to JDBC. Exposed's R2DBC support enables integration with reactive frameworks and Kotlin coroutines. Use R2DBC if:
You're building a high-concurrency, I/O-bound application.
You want to avoid thread-blocking and leverage Kotlin coroutines end-to-end.
R2DBC is still evolving, and not all databases or features are supported equally compared to JDBC.
Choose JDBC when you need simplicity, broad database compatibility, or are building a traditional application with moderate concurrency requirements. Choose R2DBC when building reactive applications, working with Kotlin coroutines, or needing to handle many concurrent connections efficiently with limited resources.
Connecting to a Database
Every database access in Exposed begins by establishing a connection and creating a transaction.
To connect to a database, you first need to tell Exposed of the connection details. You have two options:
Use
Database.connect()for traditional JDBC-based access.Use
R2dbcDatabase.connect()for reactive, non-blocking access with R2DBC.
These functions do not immediately establish a connection. Instead, they provide a descriptor for future usage. An actual connection is only established when a transaction is initiated.
To get a database instance using simple connection parameters, use the following approach:
H2
In order to use H2, you need to add the H2 driver dependency:
Then connect to a database:
Or in-memory database:
By default, H2 closes the database when the last connection is closed. If you want to keep the database open, you can use the DB_CLOSE_DELAY=-1 option:
MariaDB
Add the required dependency:
Connect to a database:
MySQL
Add the required dependency:
Connect to a database:
Oracle
Add the required dependency:
Connect to a database:
PostgreSQL
Add the required dependency:
Connect to a database:
PostgreSQL using the pgjdbc-ng JDBC driver
Add the required dependency:
Connect to a database:
SQL Server
Add the required dependency:
Connect to a database:
SQLite
Add the required dependency:
Connect to a database:
Or an in-memory database:
Set SQLite compatible isolation level: