Open-source project
davidmoten/rxjava-jdbc avatar
davidmoten/rxjava-jdbc

rxjava-jdbc turns database calls into an Observable chain

Efficient execution and functional composition of database calls using jdbc and RxJava Observables

801 stars113 forksJavaApache-2.0

At a glance

What is it?
The rxjava-jdbc library wraps JDBC so that a query becomes an Observable you can compose, pass parameters from one query into another, cancel before it runs, and map result rows into tuples or your own classes, with support for CLOB and BLOB and for transactions. It suits teams on RxJava 1 who want queries to compose rather than nest.
Who is it for?
Adopt rxjava-jdbc when your Java service already uses RxJava 1 and its database calls are the part of the codebase that is hardest to compose, since a query becomes a value you can pass into another query and cancel before it executes. Do not adopt it if you are starting a new project on RxJava 2 or 3, because this artifact targets RxJava 1 and the README points to a separate rxjava2-jdbc project for the newer line.
Can I use it commercially?
Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 24 days ago.
What is it written in?
Mainly Java, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.

Editorial analysis

A query becomes a value you can pass around

The pitch in one line is efficient execution, concise code, and functional composition of database calls using JDBC and RxJava Observables. The example the README opens with is the whole argument in a few lines:

java
Database db = Database.from(url);
List<String> names = db
		.select("select name from person where name > ? order by name")
		.parameter("ALEX")
		.getAs(String.class)
		.toList().toBlocking().single();

The same query written with plain JDBC needs a connection, a prepared statement, a result set loop and a try with resources, and the README prints that version side by side. The difference is not only the line count. In the plain version the query executes when you call `executeQuery`, and the only way to use its result elsewhere is to block on it and pass a value. In the reactive version the result is an Observable, so it can be consumed by another query, cancelled, or left unsubscribed and never run at all.

The fluent surface, and the two query kinds

There are two entry points on the `Database` object, and the README is precise about which is which. `Database.select()` is used for SQL select queries, while `Database.update()` is used for update, insert, delete and DDL such as create table. From there the chain is built with `parameter()` for a value, `parameters()` for a value that arrives later, and `getAs()` for the type you want each row mapped to. The README's feature list adds that queries can depend on the completion of other Observables and can be supplied parameters through Observables, and that method chaining just leads the way once you are on the RxJava API.

Composition: a query whose parameter is another query

This is the capability that has no JDBC equivalent, and the README's example is the clearest statement of it. The goal is to find the first person alphabetically with a score less than the person with the last name alphabetically whose name is not XAVIER, and the code does it with two threads and two connections:

java
Database db = new Database(connectionProvider);
Observable<Integer> score = db
		.select("select score from person where name <> ? order by name")
		.parameter("XAVIER")
		.getAs(Integer.class)
		.last();
String name = db
		.select("select name from person where score < ? order by name")
		.parameters(score)
		.getAs(String.class)
		.first()
		.toBlocking().single();

The second query takes its parameter from the first query's Observable, and the two run in parallel where the dependency allows it. There is also an alternative that chains everything in one command, using `Observable.compose()` with a parameter transformer so the downstream query is built from the upstream result. The functional cost is real but bounded: the composition is expressed in the type system of Observables rather than in nested callbacks, and the two forms produce the same answer.

toBlocking is a boundary, not a habit

The README spends a short section on `toBlocking` because it is the part newcomers over-use. It says you will see `toBlocking()` in the examples on the page and in the unit tests, but in your application code you should try to avoid using it, because the most benefit from the reactive style is obtained by not leaving the monad. The instruction is to stay in Observable land, chain everything together, and leave `toBlocking` to an endpoint or better still something further out. The framing is about where the blocking happens rather than whether it happens, since a servlet endpoint that returns a value still has to block somewhere. A useful test when reviewing a service built on this library is to count how many places call it, because each one is a place where the chain is cut and the concurrency stops.

Automap puts rows into your own classes

The result mapping is where the library saves the most typing. The feature list says it automatically maps query result rows into typed tuples or your own classes, and the table of contents breaks that into two modes, automap using an interface and automap using a concrete class, with an auto mappings section on top. Alongside that there is explicit mapping, where you write the mapping yourself, and a tuples section covering `Tuple2` and `TupleN` for the cases where a row is just a couple of values. The difference between explicit and automap is the usual one. Explicit mapping is more code and more control, automap is a class or interface with matching fields and the library fills it in, which is the difference between a query returning a `List<String>` and a query returning a `List<Person>` without a conversion loop in between.

Large objects, generated keys and transactions

Two JDBC areas that usually need care are called out separately. CLOB and BLOB handling is described as greatly simplified, with the table of contents listing the insert of a Clob, the insert of a null Clob, the read of a Clob, and the same three for Blob, which tells you the library has an opinionated path for each rather than leaving you to stream the values by hand. There is also a section on returning generated keys, which matters for inserts where the primary key is assigned by the database. Transactions have two documented forms, transactions as a dependency and onNext transactions, and the transaction section is where the reactive model has to be reconciled with the JDBC model, since a JDBC connection is not thread safe and cannot be shared across an asynchronous chain without care.

Connection pools, and the RxJava version question

The connection handling is a section of its own, with subsections on database connection pools, using a custom connection pool, using a single connection, and a note for SQLite users. The single connection subsection is the one to read carefully, because sharing one connection across concurrent queries is exactly the thing that breaks under load, and the library supports it as an option. On the versioning question, the README points to a separate project, rxjava2-jdbc, for RxJava 2.x with non-blocking connection pools, which tells you the two lines have diverged. This artifact uses the RxJava 1 API, with `rx.Observable` imports in the examples, and the code you write against it will not compile against RxJava 2. The build itself is Maven, with the standard three commands, and the published artifact is `com.github.davidmoten:rxjava-jdbc` on Maven Central, and the project carries an Apache 2.0 licence, a `RELEASE_NOTES.md` and release notes on GitHub.

Editorial conclusion

Adopt rxjava-jdbc when your Java service already uses RxJava 1 and its database calls are the part of the codebase that is hardest to compose, since a query becomes a value you can pass into another query and cancel before it executes. Do not adopt it if you are starting a new project on RxJava 2 or 3, because this artifact targets RxJava 1 and the README points to a separate rxjava2-jdbc project for the newer line. Verify first which RxJava version your application uses, and note that the last published release is 0.7.19 from 2022-12-09 even though the repository was pushed to on 2026-09-30, so check the release notes for what has changed since.

Frequently asked questions

What does rxjava-jdbc actually replace?

It replaces the manual connection, statement and result set handling with an Observable chain. The README's side by side example shows the same query written with plain JDBC and with the library, where the reactive version returns a value that can be composed rather than a list you have already waited for.

Can I use rxjava-jdbc with RxJava 2?

Not with this artifact. The README points to a separate project, rxjava2-jdbc, for RxJava 2.x with non-blocking connection pools. This library is built on the RxJava 1 API, with `rx.Observable` in the examples.

How do I add rxjava-jdbc to a Maven project?

Add the dependency `com.github.davidmoten:rxjava-jdbc` with the version you want, since it is published to Maven Central. To build the library from source, clone the repository, change into the directory and run `mvn clean install`.

Should I call toBlocking in my application code?

The README says to avoid it in application code, because the most benefit from the reactive style comes from not leaving the monad, and to chain everything together, leaving `toBlocking` to an endpoint or similar boundary. It appears in the examples and unit tests only.

Official sources

  1. davidmoten/rxjava-jdbc on GitHub
  2. Issues
  3. License: Apache-2.0
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/davidmoten-rxjava-jdbc.svg)](https://hysenlabs.com/projects/davidmoten-rxjava-jdbc)

Was this useful?