JDBC¶
Forage creates pooled datasources with connection management, optional XA transactions, and auxiliary repositories.
Quick Start¶
forage.myDb.jdbc.db.kind=postgresql
forage.myDb.jdbc.url=jdbc:postgresql://localhost:5432/mydb
forage.myDb.jdbc.username=admin
forage.myDb.jdbc.password=secret
Supported Databases¶
| Name | Description |
|---|---|
postgresql | PostgreSQL database |
db2 | IBM DB2 database |
h2 | H2 database |
hsqldb | HSQLDB database |
mariadb | MariaDB database |
mssql | Microsoft SQL Server database |
mysql | MySQL database |
oracle | Oracle database |
Properties¶
| Property | Description | Type | Default | Required |
|---|---|---|---|---|
forage.jdbc.db.kind | The database kind/type | bean-name | Yes | |
forage.jdbc.url | The JDBC connection URL | string | Yes | |
forage.jdbc.transaction.enabled | Enable transaction management | boolean | false | |
forage.jdbc.aggregation.repository.enabled | Enable aggregation repository (requires transactions to be enabled) | boolean | false | |
forage.jdbc.idempotent.repository.enabled | Enable idempotent repository | boolean | false | |
forage.jdbc.idempotent.repository.table.name | Table name for idempotent repository | string |
Security
| Property | Description | Type | Default | Required |
|---|---|---|---|---|
forage.jdbc.username | The database username | string | Yes | |
forage.jdbc.password | The database password | password | Yes |
Advanced
| Property | Description | Type | Default | Required |
|---|---|---|---|---|
forage.jdbc.pool.initial.size | Initial size of the connection pool | integer | 5 | |
forage.jdbc.pool.min.size | Minimum size of the connection pool | integer | 2 | |
forage.jdbc.pool.max.size | Maximum size of the connection pool | integer | 20 | |
forage.jdbc.pool.acquisition.timeout.seconds | Timeout for acquiring a connection from the pool (seconds) | integer | 5 | |
forage.jdbc.pool.validation.timeout.seconds | Timeout for validating a connection (seconds) | integer | 3 | |
forage.jdbc.pool.leak.timeout.minutes | Timeout for detecting connection leaks (minutes) | integer | 10 | |
forage.jdbc.pool.idle.validation.timeout.minutes | Timeout for validating idle connections (minutes) | integer | 3 | |
forage.jdbc.transaction.timeout.seconds | Timeout for transactions (seconds) | integer | 30 | |
forage.jdbc.transaction.node.id | The transaction node identifier | string | ||
forage.jdbc.transaction.object.store.id | The transaction object store identifier | string | ||
forage.jdbc.transaction.enable.recovery | Enable transaction recovery | boolean | false | |
forage.jdbc.transaction.recovery.period.seconds | Interval between periodic transaction recovery scans, in seconds | integer | 120 | |
forage.jdbc.transaction.recovery.backoff.seconds | Delay between the first and second pass of a recovery scan, in seconds | integer | 10 | |
forage.jdbc.transaction.recovery.modules | Comma-separated list of transaction recovery modules | string | ||
forage.jdbc.transaction.expiry.scanners | Comma-separated list of transaction expiry scanners | string | com.arjuna.ats.internal.arjuna.recovery.ExpiredTransactionStatusManagerScanner | |
forage.jdbc.transaction.xa.resource.orphan.filters | Comma-separated list of XA resource orphan filters | string | ||
forage.jdbc.transaction.object.store.directory | Directory for transaction object store | string | ObjectStore | |
forage.jdbc.transaction.object.store.type | Type of transaction object store (file-system or jdbc) | string | file-system | |
forage.jdbc.transaction.object.store.datasource | DataSource name for JDBC object store | string | ||
forage.jdbc.transaction.object.store.create.table | Create object store table if not exists | boolean | false | |
forage.jdbc.transaction.object.store.drop.table | Drop object store table on shutdown | boolean | false | |
forage.jdbc.transaction.object.store.table.prefix | Prefix for object store tables | string | forage_ | |
forage.jdbc.aggregation.repository.name | Name of the aggregation repository | string | ||
forage.jdbc.aggregation.repository.headers.to.store | Comma-separated list of headers to store | string | ||
forage.jdbc.aggregation.repository.store.body | Store message body in repository | boolean | ||
forage.jdbc.aggregation.repository.dead.letter.uri | Dead letter queue URI for failed aggregations | string | ||
forage.jdbc.aggregation.repository.allow.serialized.headers | Allow serialized headers in repository | boolean | ||
forage.jdbc.aggregation.repository.maximum.redeliveries | Maximum number of redelivery attempts | integer | ||
forage.jdbc.aggregation.repository.use.recovery | Enable recovery for aggregation repository | boolean | ||
forage.jdbc.aggregation.repository.propagation.behaviour.name | Transaction propagation behaviour name | string | ||
forage.jdbc.idempotent.repository.table.create | Create idempotent table if not exists | boolean | true | |
forage.jdbc.idempotent.repository.processor.name | Processor name for idempotent repository | string |
Unknown db.kind
Setting an unrecognized db.kind value now fails at startup with an error listing the available providers, instead of producing a NullPointerException later.
Multiple Datasources¶
Use different names to configure multiple databases:
forage.ordersDb.jdbc.db.kind=postgresql
forage.ordersDb.jdbc.url=jdbc:postgresql://db1:5432/orders
forage.analyticsDb.jdbc.db.kind=mysql
forage.analyticsDb.jdbc.url=jdbc:mysql://db2:3306/analytics
XA Transactions¶
Setting forage.jdbc.transaction.enabled=true switches the module to XA mode: the Agroal pool enlists connections in the Narayana transaction manager (initialized from the forage.jdbc.transaction.* properties), and JTA transaction policies (PROPAGATION_REQUIRED, REQUIRES_NEW, ...) are registered for use with the transacted EIP.
Crash Recovery¶
If the application crashes between the prepare and commit phase of an XA transaction, the transaction branch is left in doubt on the database until someone resolves it. Setting forage.jdbc.transaction.enable.recovery=true makes Forage run Narayana's periodic recovery in-process:
- A recovery manager is started once per JVM (shared with the JMS module) as soon as the first XA-enabled datasource is created, and stopped when the Camel context stops (or the Spring application context closes).
- Every XA-enabled datasource — including named/prefixed ones — is registered with the recovery manager through Agroal's Narayana integration, so Narayana can obtain fresh connections and resolve in-doubt branches after a restart.
- Every
forage.jdbc.transaction.recovery.period.seconds(default 120) a recovery scan replays the transaction log: branches whose commit decision was recorded are committed, unresolved prepared branches are rolled back once the orphan filters approve.
For recovery to work across restarts:
- The object store must be persistent and stable.
forage.jdbc.transaction.object.store.directorydefaults toObjectStore, resolved against the process working directory — in production point it to an absolute path on durable storage, and make sure the restarted instance uses the same directory. forage.jdbc.transaction.node.idmust be stable and unique per node. Narayana tags every transaction branch with it; a restarted instance only recovers branches created under the same node id, and two nodes sharing an id would steal each other's transactions.
With forage.jdbc.transaction.enable.recovery=false (the default) no recovery thread is started.
Quarkus
On Quarkus, recovery is owned by the quarkus-narayana-jta extension: Forage translates enable.recovery, the object store settings, and the node id to the corresponding quarkus.transaction-manager.* properties. The recovery scan interval is not configurable through Quarkus properties — use the Narayana system property -DRecoveryEnvironmentBean.periodicRecoveryPeriod=<seconds> if you need to change it.