Quarkus - Datasources

Many projects that use data require connections to a relational database.

The main way of obtaining connections to a database is to use a datasource and configure a JDBC driver.

In Quarkus, the preferred datasource and connection pooling implementation is Agroal.

Agroal is a modern, light weight connection pool implementation designed for very high performance and scalability,and features first class integration with the other components in Quarkus, such as security, transaction management components, health metrics.

This guide will explain how to:

  • configure a datasource, or multiple datasources

  • how to obtain a reference to those datasources in code

  • which pool tuning configuration properties are available

Prerequisites

To complete this guide, you will need:

  • less than 10 minutes

  • an IDE

  • JDK 1.8+ installed with JAVA_HOME configured appropriately

  • Apache Maven 3.5.3+

Creating the Maven project

First, we need a new project. Create a new project with the following command:

  1. mvn io.quarkus:quarkus-maven-plugin:1.0.0.CR1:create \
  2. -DprojectGroupId=org.acme \
  3. -DprojectArtifactId=agroal-quickstart \
  4. -DclassName="org.acme.datasource.GreetingResource" \
  5. -Dpath="/hello"
  6. cd agroal-quickstart

This will generate:

  • the Maven structure

  • a landing page accessible on http://localhost:8080

  • an example Dockerfile files for both native and jvm modes

  • the application configuration file

  • an org.acme.datasource.GreetingResource resource

  • an example integration test

Adding maven dependencies

Next, you will need to add the quarkus-agroal dependency to your project.

You can add it using a simple Maven command:

  1. ./mvnw quarkus:add-extension -Dextensions="agroal"
Agroal comes as a transitive dependency of the Hibernate ORM extension so if you are using Hibernate ORM,you don’t need to add the Agroal extension dependency explicitly.

You will also need to choose, and add, the Quarkus extension for your relational database driver.

Quarkus provides driver extensions for:

  • H2 - jdbc-h2

  • PostgreSQL - jdbc-postgresql

  • MariaDB - jdbc-mariadb

  • MySQL - jdbc-mysql

  • Microsoft SQL Server - jdbc-mssql

  • Derby - jdbc-derby

The H2 and Derby databases can normally be configured to run in "embedded mode"; the extension does not support compiling the embedded database engine into native images.Read Testing with in-memory databases (below) for suggestions regarding integration testing.

As usual, you can install the extension using add-extension.

To install the PostgreSQL driver dependency for instance, just run the following command:

  1. ./mvnw quarkus:add-extension -Dextensions="jdbc-postgresql"

Configuring the datasource

Once the dependencies are added to your pom.xml file, you’ll need to configure Agroal.

This is done in the src/main/resources/application.properties file.

A viable configuration file would be:

  1. quarkus.datasource.url=jdbc:h2:tcp://localhost/mem:default
  2. quarkus.datasource.driver=org.h2.Driver
  3. quarkus.datasource.username=username-default
  4. quarkus.datasource.min-size=3
  5. quarkus.datasource.max-size=13

There are other configuration options, detailed below.

For more information about the Agroal extension configuration please refer to the Configuration Reference.

JDBC URL configurations

Each of the supported databases contains different JDBC URL configuration options.Going into each of those options is beyond the scope of this document, but it gives an overview of each database URL and link to the official documentation.

H2

jdbc:h2:{ {.|mem:}[name] | [file:]fileName | {tcp|ssl}:[//]server[:port][,server2[:port]]/name }[;key=value…​]

  • Example
  • jdbc:h2:tcp://localhost/~/test, jdbc:h2:mem:myDB

H2 is an embedded database.It can run as a server, based on a file, or live completely in memory.All of these options are available as listed above.You can find more information at the official documentation.

PostgreSQL

PostgreSQL only runs as a server, as do the rest of the databases below.As such, you must specify connection details, or use the defaults.

jdbc:postgresql:[//][host][:port][/database][?key=value…​]

  • Example
  • jdbc:postgresql://localhost/test

Defaults for the different parts are as follows:

  • host
  • localhost

  • port

  • 5432

  • database

  • same name as the username

The official documentation go into more detail and list optional parameters as well.

MariaDB

jdbc:mariadb:[replication:|failover:|sequential:|aurora:]//<hostDescription>[,<hostDescription>…​]/[database][?<key1>=<value1>[&<key2>=<value2>]] hostDescription:: <host>[:<portnumber>] or address=(host=<host>)[(port=<portnumber>)][(type=(master|slave))]

  • Example
  • jdbc:mariadb://localhost:3306/test

You can find more information about this feature and others detailed in the official documentation.

MySQL

jdbc:mysql:[replication:|failover:|sequential:|aurora:]//<hostDescription>[,<hostDescription>…​]/[database][?<key1>=<value1>[&<key2>=<value2>]] hostDescription:: <host>[:<portnumber>] or address=(host=<host>)[(port=<portnumber>)][(type=(master|slave))]

  • Example
  • jdbc:mysql://localhost:3306/test

You can find more information about this feature and others detailed in the official documentation.

Microsoft SQL Server

Microsoft SQL Server takes a connection URL in the following form:

jdbc:sqlserver://[serverName[\instanceName][:portNumber]][;property=value[;property=value]]

  • Example
  • jdbc:sqlserver://localhost:1433;databaseName=AdventureWorks

The Microsoft SQL Server JDBC driver works essentially the same as the others.More details can be found in the official documentation.

Derby

jdbc:derby:[//serverName[:portNumber]/][memory:]databaseName[;property=value[;property=value]]

  • Example
  • jdbc:derby://localhost:1527/myDB, jdbc:derby:memory:myDB;create=true

Derby is an embedded database.It can run as a server, based on a file, or live completely in memory.All of these options are available as listed above.You can find more information at the official documentation.

Injecting a Datasource

Because Quarkus uses CDI, injecting a datasource is very simple:

  1. @Inject
  2. AgroalDataSource defaultDataSource;

In the above example, the type is AgroalDataSource which is a subtype of javax.sql.DataSource.Because of this, you can also use javax.sql.DataSource.

Multiple Datasources

Agroal allows you to configure multiple datasources.It works exactly the same way as a single datasource, with one important change: a name.

  1. quarkus.datasource.driver=org.h2.Driver
  2. quarkus.datasource.url=jdbc:h2:tcp://localhost/mem:default
  3. quarkus.datasource.username=username-default
  4. quarkus.datasource.min-size=3
  5. quarkus.datasource.max-size=13
  6. quarkus.datasource.users.driver=org.h2.Driver
  7. quarkus.datasource.users.url=jdbc:h2:tcp://localhost/mem:users
  8. quarkus.datasource.users.username=username1
  9. quarkus.datasource.users.min-size=1
  10. quarkus.datasource.users.max-size=11
  11. quarkus.datasource.inventory.driver=org.h2.Driver
  12. quarkus.datasource.inventory.url=jdbc:h2:tcp://localhost/mem:inventory
  13. quarkus.datasource.inventory.username=username2
  14. quarkus.datasource.inventory.min-size=2
  15. quarkus.datasource.inventory.max-size=12

Notice there’s an extra bit in the key.The syntax is as follows: quarkus.datasource.[optional name.][datasource property].

Named Datasource Injection

When using multiple datasources, each DataSource also has the io.quarkus.agroal.DataSource qualifier with the name of the datasource in the property as the value.Using the above properties to configure three different datasources, you can also inject each one as follows:

  1. @Inject
  2. AgroalDataSource defaultDataSource;
  3. @Inject
  4. @DataSource("users")
  5. AgroalDataSource dataSource1;
  6. @Inject
  7. @DataSource("inventory")
  8. AgroalDataSource dataSource2;

Datasource Health Check

If you are using the quarkus-smallrye-health extension, quarkus-agroal will automatically add a readiness health checkto validate the datasource.

So when you access the /health/ready endpoint of your application you will have information about the datasource validation status.If you have multiple datasources, all datasources will be checked and the status will be DOWN as soon as there is one datasource validation failure.

This behavior can be disabled via the property quarkus.datasource.health.enabled.

Narayana Transaction Manager integration

If the Narayana JTA extension is also available, integration is automatic.

You can override this by setting the transactions configuration property - see the Configuration Reference below.

Testing with in-memory databases

Some databases like H2 and Derby are commonly used in "embedded mode" as a facility to run quick integration tests.

Our suggestion is to use the real database you intend to use in production; container technologies made this simple enough so you no longer have an excuse. Still, there are sometimesgood reasons to also want the ability to run quick integration tests using the JVM powered databases,so this is possible as well.

It is important to remember that when configuring H2 (or Derby) to use the embedded engine,this will work as usual in JVM mode but such an application will not compile into a native image, as the Quarkus extensions only cover for making the JDBC client code compatible with the native compilation step: embedding the whole database engine into a native image is currently not implemented.

If you plan to run such integration tests in the JVM exclusively, it will of course work as usual.

If you want the ability to run such integration test in both JVM and/or native images, we have some cool helpers for you: just add either @QuarkusTestResource(H2DatabaseTestResource.class) or @QuarkusTestResource(DerbyDatabaseTestResource.class) on any class in your integration tests, this will make sure the testsuite starts (and stops) the embedded database into a separate process as necessary to run your tests.

These additional helpers are provided by the artifacts having Maven coordinates io.quarkus:quarkus-test-h2:1.0.0.CR1 and io.quarkus:quarkus-test-derby:1.0.0.CR1, respectively for H2 and Derby.

Follows an example for H2:

  1. package my.app.integrationtests.db;
  2. import io.quarkus.test.common.QuarkusTestResource;
  3. import io.quarkus.test.h2.H2DatabaseTestResource;
  4. @QuarkusTestResource(H2DatabaseTestResource.class)
  5. public class TestResources {
  6. }

This will allow you to test your application even when it’s compiled into a native image,while the database will run in the JVM as usual.

Connect to it using:

  1. quarkus.datasource.url=jdbc:h2:tcp://localhost/mem:test
  2. quarkus.datasource.driver=org.h2.Driver

Agroal Configuration Reference

Configuration property fixed at build time - ️ Configuration property overridable at runtime

Configuration propertyTypeDefault
quarkus.datasource.driverThe datasource driver class namestring
quarkus.datasource.transactionsWhether we want to use regular JDBC transactions, XA, or disable all transactional capabilities. When enabling XA you will need a driver implementing javax.sql.XADataSource.enabled, xa, disabledenabled
quarkus.datasource.health.enabledWhether or not an healtcheck is published in case the smallrye-health extension is present (default to true).booleantrue
quarkus.datasource.urlThe datasource URLstring
quarkus.datasource.usernameThe datasource usernamestring
quarkus.datasource.passwordThe datasource passwordstring
quarkus.datasource.credentials-providerThe credentials provider namestring
quarkus.datasource.credentials-provider-typeThe credentials provider type. It is the @Named value of the credentials provider bean. It is used to discriminate if multiple CredentialsProvider beans are available. For Vault it is: vault-credentials-provider. Not necessary if there is only one credentials provider available.string
quarkus.datasource.initial-sizeThe initial size of the pool. Usually you will want to set the initial size to match at least the minimal size, but this is not enforced so to allow for architectures which prefer a lazy initialization of the connections on boot, while being able to sustain a minimal pool size after boot.int
quarkus.datasource.min-sizeThe datasource pool minimum sizeint0
quarkus.datasource.max-sizeThe datasource pool maximum sizeint20
quarkus.datasource.background-validation-intervalThe interval at which we validate idle connections in the background. Set to 0 to disable background validation.Duration2M
quarkus.datasource.acquisition-timeoutThe timeout before cancelling the acquisition of a new connectionDuration5
quarkus.datasource.leak-detection-intervalThe interval at which we check for connection leaks.Duration
quarkus.datasource.idle-removal-intervalThe interval at which we try to remove idle connections.Duration5M
quarkus.datasource.max-lifetimeThe max lifetime of a connection.Duration
quarkus.datasource.transaction-isolation-levelThe transaction isolation level.undefined, none, read-uncommitted, read-committed, repeatable-read, serializable
quarkus.datasource.enable-metricsEnable datasource metrics collection.booleanfalse
quarkus.datasource.detect-statement-leaksWhen enabled Agroal will be able to produce a warning when a connection is returned to the pool without the application having closed all open statements. This is unrelated with tracking of open connections. Disable for peak performance, but only when there’s high confidence that no leaks are happening.booleantrue
quarkus.datasource.new-connection-sqlQuery executed when first using a connection.string
Additional named datasourcesTypeDefault
quarkus.datasource."datasource-name".driverThe datasource driver class namestring
quarkus.datasource."datasource-name".transactionsWhether we want to use regular JDBC transactions, XA, or disable all transactional capabilities. When enabling XA you will need a driver implementing javax.sql.XADataSource.enabled, xa, disabledenabled
quarkus.datasource."datasource-name".urlThe datasource URLstring
quarkus.datasource."datasource-name".usernameThe datasource usernamestring
quarkus.datasource."datasource-name".passwordThe datasource passwordstring
quarkus.datasource."datasource-name".credentials-providerThe credentials provider namestring
quarkus.datasource."datasource-name".credentials-provider-typeThe credentials provider type. It is the @Named value of the credentials provider bean. It is used to discriminate if multiple CredentialsProvider beans are available. For Vault it is: vault-credentials-provider. Not necessary if there is only one credentials provider available.string
quarkus.datasource."datasource-name".initial-sizeThe initial size of the pool. Usually you will want to set the initial size to match at least the minimal size, but this is not enforced so to allow for architectures which prefer a lazy initialization of the connections on boot, while being able to sustain a minimal pool size after boot.int
quarkus.datasource."datasource-name".min-sizeThe datasource pool minimum sizeint0
quarkus.datasource."datasource-name".max-sizeThe datasource pool maximum sizeint20
quarkus.datasource."datasource-name".background-validation-intervalThe interval at which we validate idle connections in the background. Set to 0 to disable background validation.Duration2M
quarkus.datasource."datasource-name".acquisition-timeoutThe timeout before cancelling the acquisition of a new connectionDuration5
quarkus.datasource."datasource-name".leak-detection-intervalThe interval at which we check for connection leaks.Duration
quarkus.datasource."datasource-name".idle-removal-intervalThe interval at which we try to remove idle connections.Duration5M
quarkus.datasource."datasource-name".max-lifetimeThe max lifetime of a connection.Duration
quarkus.datasource."datasource-name".transaction-isolation-levelThe transaction isolation level.undefined, none, read-uncommitted, read-committed, repeatable-read, serializable
quarkus.datasource."datasource-name".enable-metricsEnable datasource metrics collection.booleanfalse
quarkus.datasource."datasource-name".detect-statement-leaksWhen enabled Agroal will be able to produce a warning when a connection is returned to the pool without the application having closed all open statements. This is unrelated with tracking of open connections. Disable for peak performance, but only when there’s high confidence that no leaks are happening.booleantrue
quarkus.datasource."datasource-name".new-connection-sqlQuery executed when first using a connection.string
About the Duration formatThe format for durations uses the standard java.time.Duration format.You can learn more about it in the Duration#parse() javadoc.You can also provide duration values starting with a number.In this case, if the value consists only of a number, the converter treats the value as seconds.Otherwise, PT is implicitly prepended to the value to obtain a standard java.time.Duration format.