All of the examples mentioned here - and a lot more besides - are in a GitHub repository.
I ignored jOOQ for quite a long time - mainly because I was happy using Jdbi (and still am); and then later on because I spent time using Hibernate ORM (which was easy to get up-and-running but hard to get right).
I still find it faster to write native SQL than to write jOOQ’s SQL-as-Java - but there are many really great things in jOOQ which I appreciate. What caught my eye recently was this article: jOOQ 3.15’s New Multiset Operator Will Change How You Think About SQL - which is a few years old, at this point, but still was something I really wanted to try for myself: returning more complex nested result sets, without having to wrangle all that JSON-related syntax provided by vendors (such as those provided by MySQL).
There were also other things which caught my eye, including:
I have to confess, writing type-safe SQL was not so high on the list of things that interested me - although I do see how powerful that can be.
The first thing I did was to set up my own copy of the Sakila database.
Specifically, I used the scripts for MySQL.
I used MySQL v8.4.
(And Java 21.)
I wanted to see how to use jOOQ’s code generation options.
There are various different ways to run the code generator. I chose to use the command line. To do that, I first wrote a small Maven script to collect the JAR files needed to run the generator:
The jars-pom.xml
POM collects the required JAR files and places them in a lib/
subdirectory. The following command does this:
|
|
This is a one-time process. I don’t need to do this again unless I need to download newer versions of any of the JARs.
Now I can run jOOQ generation commands such the ones shown in the next sections.
I did not need to do this, but I wanted to.
jOOQ can generate an XML representation of my schema. To do this I created the following jOOQ configuration file:
The following command uses the above jooq-xml-schema-config.xml
file:
|
|
The config file contains JDBC connection details for my Sakila database. jOOQ connects to the DB and extracts all of the relevant schema data.
You can see the results for my Sakila database here.
This XML data can be used later on (see below) to actually generate the Java code for jOOQ (and for me) to use.
You don’t have to use this type of XML file to generate jOOQ code. You can generate code directly from the database itself - and I expect that is what most people do. But (as noted earlier) I wanted to try this, out of curiosity.
A new jOOQ config schema is needed to do this.
My example is here: jooq-classes-config.xml
There are many ways to configure this file, for many different purposes and behaviors. Mine is relatively simple.
The generation command:
|
|
Some points to note from the config file:
jOOQ Record
Classes
jOOQ generates one jOOQ Record
class for each table and view in the related schema. Each class contains information about the columns in each table and view.
In this context, Record
means a relational table record (e.g. a row of data). These days, this is somewhat unfortunate, since this jOOQ Record
is based on the jOOQ class org.jooq.Record;
. Nowadays, this clashes with Java’s newer Record
type (which is a totally different thing).
You will see in my jOOQ-related code that I always explicitly add the following import to avoid naming collisions:
|
|
jOOQ Table
Classes
jOOQ generates one jOOQ Table
class for each table and view it exports. These classes also help to support strongly typed Java when you write your jOOQ SQL code.
So, for the DB table ACTOR
, jOOQ generates the file Actor.class
.
Since I wanted jOOQ to also generate Java POJOs, I wanted to distinguish the jOOQ table classes from my POJO classes. They would both be in different packages - but would both be called (for example) Actor.class
.
So, I chose to make jOOQ generate its table classes using a suffix of Table
, so I would not be juggling two different classes (e.g. called Actor.class
).
You can see this in the jOOQ config file here. First, jOOQ adds a suffix of _TABLE
to the database table name; and then jOOQ uses Pascal case formatting to change that into a string suitable to be used as a Java table name.
jOOQ Generated POJOs
I was not sure how I was going to use the POJOs I chose to generate.
It turns out they were mainly useful as templates for generating custom POJOs - and I found myself using jOOQ’s Record
classes (and UpdatableRecord
subclasses) most of the time.
As it mentions in one section of the jOOQ manual, when discussing DAOs and POJOs:
It’s perfectly fine to work with
org.jooq.UpdatableRecord
directly, or with SQL statements, instead!
I tried various things, but ended up simply copying the generated classes into the main “Sources” structure (under src/main/java/
), under their own package hierarchy.
I considered doing what Hibernate does - which is to place all generated classes in a parallel generated-sources
structure, but ended up keeping things simpler than that.
All of the jOOQ SQL samples I wrote are runnable against my Sakila database.
You can see them all in JooqExamples.java.
The main
entrypoint is here: Sakila.java
I arranged the queries into the following broad categories:
If you look at the “nested Java records” section, you can see some of the really cool ways in which jOOQ leverages a database’s built-in nesting capabilities (e.g. via JSON handing, for MySQL).
Here is one:
|
|
The best walkthrough of what is going on here is in the article I mentioned at the start: jOOQ 3.15’s New Multiset Operator Will Change How You Think About SQL