ai/JDBC_CONFIGURATION.md
This document describes the configuration format for JDBC database connections in Conductor.
Conductor supports configuring multiple named JDBC instances for use by the JDBC worker task. This allows you to:
JDBC instances are configured using a list-based approach under conductor.jdbc.instances:
conductor:
jdbc:
instances:
- name: "instance-name" # Unique identifier for this instance
connection: # Connection configuration
datasourceURL: "jdbc:..." # JDBC connection URL
jdbcDriver: "..." # JDBC driver class (optional, auto-detected from URL)
user: "..." # Database username
password: "..." # Database password
# ... pool settings
conductor:
jdbc:
instances:
- name: "mysql-prod"
connection:
datasourceURL: "jdbc:mysql://prod-db:3306/myapp"
jdbcDriver: "com.mysql.cj.jdbc.Driver"
user: "conductor"
password: "secret"
maximumPoolSize: 20
minimumIdle: 5
conductor:
jdbc:
instances:
- name: "mysql-prod"
connection:
datasourceURL: "jdbc:mysql://prod-db:3306/myapp"
jdbcDriver: "com.mysql.cj.jdbc.Driver"
user: "conductor"
password: "prod-secret"
maximumPoolSize: 20
- name: "postgres-analytics"
connection:
datasourceURL: "jdbc:postgresql://analytics-db:5432/warehouse"
user: "analyst"
password: "analytics-secret"
maximumPoolSize: 10
- name: "mysql-staging"
connection:
datasourceURL: "jdbc:mysql://staging-db:3306/myapp"
jdbcDriver: "com.mysql.cj.jdbc.Driver"
user: "conductor"
password: "staging-secret"
maximumPoolSize: 5
minimumIdle: 1
When using the JDBC task in your workflows, reference the instance by its configured name using connectionId:
{
"name": "query_users",
"taskReferenceName": "query_users_ref",
"type": "JDBC",
"inputParameters": {
"connectionId": "mysql-prod",
"type": "SELECT",
"statement": "SELECT id, name, email FROM users WHERE status = ?",
"parameters": ["active"]
}
}
{
"name": "find_orders",
"taskReferenceName": "find_orders_ref",
"type": "JDBC",
"inputParameters": {
"connectionId": "postgres-analytics",
"type": "SELECT",
"statement": "SELECT order_id, total FROM orders WHERE customer_id = ?",
"parameters": ["${workflow.input.customerId}"]
}
}
Output:
{
"result": [
{"order_id": 101, "total": 49.99},
{"order_id": 205, "total": 129.50}
]
}
{
"name": "update_status",
"taskReferenceName": "update_status_ref",
"type": "JDBC",
"inputParameters": {
"connectionId": "mysql-prod",
"type": "UPDATE",
"statement": "UPDATE orders SET status = ? WHERE order_id = ?",
"parameters": ["shipped", "${workflow.input.orderId}"],
"expectedUpdateCount": 1
}
}
Output:
{
"update_count": 1
}
If the actual update count does not match expectedUpdateCount, the transaction is rolled back and the task fails.
| Property | Type | Default | Description |
|---|---|---|---|
datasourceURL | String | Required | JDBC connection URL |
jdbcDriver | String | Auto-detected | JDBC driver class name |
user | String | Optional | Database username |
password | String | Optional | Database password |
maximumPoolSize | Integer | 32 | Maximum connections in the pool |
minimumIdle | Integer | 2 | Minimum idle connections |
idleTimeoutMs | Long | 30000 | Idle connection timeout (ms) |
connectionTimeout | Long | 30000 | Connection acquisition timeout (ms) |
leakDetectionThreshold | Long | 60000 | Leak detection threshold (ms) |
maxLifetime | Long | 1800000 | Maximum connection lifetime (ms) |
conductor.worker.jdbc.connectionIds=mysql,postgres
conductor.worker.jdbc.mysql.connectionURL=jdbc:mysql://localhost:3306/db
conductor.worker.jdbc.mysql.driverClassName=com.mysql.cj.jdbc.Driver
conductor.worker.jdbc.mysql.username=root
conductor.worker.jdbc.mysql.password=secret
conductor.worker.jdbc.mysql.maximum-pool-size=10
conductor.worker.jdbc.postgres.connectionURL=jdbc:postgresql://localhost:5432/db
conductor.worker.jdbc.postgres.driverClassName=org.postgresql.Driver
conductor.worker.jdbc.postgres.username=pguser
conductor.worker.jdbc.postgres.password=pgpass
conductor:
jdbc:
instances:
- name: "mysql"
connection:
datasourceURL: "jdbc:mysql://localhost:3306/db"
jdbcDriver: "com.mysql.cj.jdbc.Driver"
user: "root"
password: "secret"
maximumPoolSize: 10
- name: "postgres"
connection:
datasourceURL: "jdbc:postgresql://localhost:5432/db"
jdbcDriver: "org.postgresql.Driver"
user: "pguser"
password: "pgpass"
Note: The old conductor.worker.jdbc.* format is still supported for backwards compatibility. If no conductor.jdbc.instances are configured, the system automatically falls back to reading the legacy format. The old and new formats are mutually exclusive -- if new-format instances are found, the legacy format is ignored.
| Old Property | New Property |
|---|---|
connectionURL | datasourceURL |
driverClassName | jdbcDriver |
username | user |
password | password |
maximum-pool-size | maximumPoolSize |
idle-timeout-ms | idleTimeoutMs |
minimum-idle | minimumIdle |
Use descriptive names: Choose instance names that clearly indicate their purpose (e.g., mysql-prod, postgres-analytics, oracle-reporting)
Separate read/write pools: For high-throughput systems, configure separate instances for read and write operations with appropriate pool sizes
Right-size connection pools: Set maximumPoolSize based on your database capacity and workload. A common formula is connections = (core_count * 2) + effective_spindle_count
Enable leak detection: The default leakDetectionThreshold of 60 seconds logs warnings for connections held longer than expected
Use parameterized queries: Always use ? placeholders with the parameters list instead of string concatenation to prevent SQL injection
Set expectedUpdateCount: For critical UPDATE/INSERT/DELETE operations, set expectedUpdateCount to automatically rollback if the affected row count doesn't match
If you see "JDBC instance not found: xyz", check:
connectionId in your workflow matches the configured name exactlyIf connections are timing out:
connectionTimeout value (default 30 seconds)maximumPoolSize if needed)If you see leak detection warnings:
leakDetectionThreshold setting