JDBC Connector¶
Reads and writes any database that has a JDBC driver (Java's standard way to talk
to a database): PostgreSQL, MySQL, Oracle, SQL Server, Redshift, Snowflake, and
more. Needs Spark. Passwords are given as secret://
references.
Read¶
CONFIG:
inputs:
customers:
format: jdbc
url: "jdbc:postgresql://db-host:5432/mydb"
table: public.customers # or use sql:
user: "{{ env.DB_USER }}"
password: "secret://env/DB_PASS"
options:
fetchsize: "10000"
Parallelised read (requires a numeric partition column). The tuning keys can be
top-level keys or go under options; both reach Spark the same way:
large_table:
format: jdbc
url: "jdbc:postgresql://db-host:5432/mydb"
table: public.transactions
user: "{{ env.DB_USER }}"
password: "secret://env/DB_PASS"
options:
partitionColumn: id
lowerBound: "1"
upperBound: "10000000"
numPartitions: "16"
fetchsize: "50000"
Custom SQL:
recent_orders:
format: jdbc
url: "jdbc:postgresql://db-host:5432/mydb"
sql: "SELECT * FROM orders WHERE created_at >= '{{ dt }}'"
user: "{{ env.DB_USER }}"
password: "secret://env/DB_PASS"
Requirement
url is required. A read needs table (or dbtable) or sql. A write
needs table.
Write¶
CONFIG:
outputs:
predictions:
format: jdbc
url: "jdbc:postgresql://db-host:5432/mydb"
table: ml.predictions
user: "{{ env.DB_USER }}"
password: "secret://env/DB_PASS"
mode: append
options:
batchsize: "5000"
truncate: "true"
A batch that lands once¶
Spark's JDBC writer commits each partition on its own, so a plain append that fails
part way leaves part of the batch, and a rerun inserts it again. Name the batch's
rows with replace_where and the append lands once:
payments:
format: jdbc
url: "jdbc:postgresql://db-host:5432/billing"
table: billing.payments
mode: append
replace_where: "month = '{{ dt }}'"
Spark writes the batch into a staging table beside the target
(ubunye_stage_<id>, same schema), then one database transaction deletes the rows
the predicate selects and inserts the staged rows. It commits or changes nothing,
and the staging table is dropped. A retry after a crash, and --rerun of a finished
batch, replace the batch from the current data. The predicate is SQL in your
database's dialect. The database user needs to create and drop a table in the
target's schema. A staging table a killed run left behind holds no target data; the
next run of the batch replaces it. Without replace_where an append is Spark's own,
as before.
Fields¶
| Field | Type | Required | Description |
|---|---|---|---|
format |
"jdbc" |
Yes | Selects this connector |
url |
string | Yes | JDBC connection URL |
table |
string | Conditional | Fully qualified table name (required for writes; for reads unless sql is set) |
dbtable |
string | No | Spark's own name for table; reads accept either |
sql |
string | Conditional | SQL query, reads only (alternative to table) |
driver |
string | No | JDBC driver class, e.g. org.postgresql.Driver |
user |
string | No | Database username |
password |
string | No | Database password, as a secret:// reference (secret://env/DB_PASS, secret://aws-sm/prod/db#password) |
fetchsize, partitionColumn, lowerBound, upperBound, numPartitions |
string or int | No | Read tuning, passed to Spark |
mode |
append | overwrite | errorifexists | ignore |
No | Default append. Spark's native save modes only; merge and overwrite_partitions are refused by this connector. ubunye plan catches that before a run; ubunye validate does not (write modes) |
replace_where |
string | No | On an append: SQL selecting the batch's rows; the batch is staged, then those rows are replaced in one transaction (above) |
options |
dict | No | Spark JDBC options, applied last |
JDBC URLs by database¶
| Database | URL pattern |
|---|---|
| PostgreSQL | jdbc:postgresql://host:5432/db |
| MySQL | jdbc:mysql://host:3306/db |
| Oracle | jdbc:oracle:thin:@host:1521/SID |
| SQL Server | jdbc:sqlserver://host:1433;databaseName=db |
| Redshift | jdbc:redshift://cluster.id.region.redshift.amazonaws.com:5439/db |
JDBC driver setup¶
The JDBC driver JAR must be on the Spark classpath:
ENGINE:
spark_conf:
spark.jars: "/opt/spark/jars/postgresql-42.7.0.jar"
# or for multiple JARs:
# spark.jars: "/opt/spark/jars/pg.jar,/opt/spark/jars/mysql.jar"
spark.jars is fixed when the Spark session starts (see
Spark keys fixed at session start).
On Databricks, install the driver via the cluster Libraries UI; elsewhere pass it
to spark-submit --jars.