Top Related Projects
MyBatis SQL mapper framework for Java
Hibernate's core Object/Relational Mapping functionality
Unified Queries for Java
The Jdbi library provides convenient, idiomatic access to relational databases in Java and other JVM technologies such as Kotlin, Clojure or Scala.
requery - modern SQL based query & persistence for Java / Kotlin / Android
Quick Overview
jOOQ (Java Object Oriented Querying) is a database-mapping software library for Java that implements the active record pattern. It provides a fluent API for building type-safe SQL queries through its domain-specific language (DSL), which emulates SQL in Java code.
Pros
- Type-safe SQL queries in Java, reducing runtime errors
- Seamless integration with Java IDEs for code completion and refactoring
- Support for advanced SQL features and database-specific functions
- Code generation from existing database schemas
Cons
- Learning curve for developers new to the DSL syntax
- Potential performance overhead compared to raw SQL queries
- Limited support for NoSQL databases
- May be overkill for simple database operations
Code Examples
- Simple SELECT query:
Result<Record> result = create.select()
.from(AUTHOR)
.where(AUTHOR.FIRST_NAME.eq("John"))
.fetch();
- JOIN operation:
Result<Record> result = create.select(AUTHOR.NAME, BOOK.TITLE)
.from(AUTHOR)
.join(BOOK).on(AUTHOR.ID.eq(BOOK.AUTHOR_ID))
.fetch();
- INSERT with returning clause:
AuthorRecord author = create.insertInto(AUTHOR)
.set(AUTHOR.FIRST_NAME, "John")
.set(AUTHOR.LAST_NAME, "Doe")
.returning(AUTHOR.ID)
.fetchOne();
- Complex SELECT with subquery and aggregation:
Result<Record2<String, Integer>> result =
create.select(AUTHOR.NAME, DSL.count())
.from(AUTHOR)
.join(BOOK).on(AUTHOR.ID.eq(BOOK.AUTHOR_ID))
.where(BOOK.PUBLISHED_IN.gt(
select(avg(BOOK.PUBLISHED_IN)).from(BOOK)
))
.groupBy(AUTHOR.NAME)
.fetch();
Getting Started
- Add jOOQ dependency to your project (Maven example):
<dependency>
<groupId>org.jooq</groupId>
<artifactId>jooq</artifactId>
<version>3.17.6</version>
</dependency>
- Configure your database connection:
Connection conn = DriverManager.getConnection("jdbc:postgresql:database", "user", "password");
DSLContext create = DSL.using(conn, SQLDialect.POSTGRES);
- Start writing queries:
Result<Record> result = create.select().from(AUTHOR).fetch();
for (Record r : result) {
String firstName = r.getValue(AUTHOR.FIRST_NAME);
String lastName = r.getValue(AUTHOR.LAST_NAME);
System.out.println(firstName + " " + lastName);
}
Competitor Comparisons
MyBatis SQL mapper framework for Java
Pros of MyBatis
- More flexible SQL mapping, allowing for complex queries and stored procedures
- Easier integration with legacy databases and existing SQL
- Simpler learning curve for developers familiar with SQL
Cons of MyBatis
- More verbose XML configuration compared to jOOQ's fluent API
- Less type-safe than jOOQ, with potential for runtime errors
- Limited support for database-agnostic queries
Code Comparison
MyBatis:
<select id="selectPerson" parameterType="int" resultType="hashmap">
SELECT * FROM PERSON WHERE ID = #{id}
</select>
jOOQ:
Result<Record> result = create.select()
.from(PERSON)
.where(PERSON.ID.eq(id))
.fetch();
MyBatis relies on XML mappings for SQL queries, while jOOQ uses a fluent Java API. jOOQ provides better type safety and IDE support, but MyBatis offers more flexibility for complex SQL statements and stored procedures. MyBatis is often preferred for projects with existing SQL or complex database interactions, while jOOQ shines in new projects or when working with multiple database types.
Hibernate's core Object/Relational Mapping functionality
Pros of Hibernate ORM
- Full-featured ORM with robust object-relational mapping capabilities
- Supports automatic database schema generation and management
- Extensive caching mechanisms for improved performance
Cons of Hibernate ORM
- Steeper learning curve due to complex configuration and concepts
- Can lead to performance issues if not properly optimized
- Less control over generated SQL queries
Code Comparison
Hibernate ORM example:
@Entity
public class User {
@Id
private Long id;
private String name;
}
Session session = sessionFactory.openSession();
User user = session.get(User.class, 1L);
jOOQ example:
Record record = dsl.select()
.from(USER)
.where(USER.ID.eq(1L))
.fetchOne();
User user = record.into(User.class);
Hibernate ORM focuses on object-relational mapping, while jOOQ provides a more SQL-centric approach. Hibernate abstracts database operations through entities and annotations, whereas jOOQ offers type-safe SQL query building. The choice between the two depends on project requirements, team expertise, and desired level of database abstraction.
Unified Queries for Java
Pros of Querydsl
- More flexible and supports a wider range of databases and frameworks
- Better integration with JPA and Hibernate
- Easier to learn and use for developers familiar with Java syntax
Cons of Querydsl
- Less powerful SQL generation capabilities
- Smaller community and fewer resources compared to jOOQ
- Limited support for advanced database features
Code Comparison
Querydsl:
QCustomer customer = QCustomer.customer;
List<Customer> results = queryFactory.selectFrom(customer)
.where(customer.lastName.eq("Smith"))
.orderBy(customer.firstName.asc())
.fetch();
jOOQ:
Result<Record> result = create.select()
.from(CUSTOMER)
.where(CUSTOMER.LAST_NAME.eq("Smith"))
.orderBy(CUSTOMER.FIRST_NAME.asc())
.fetch();
Both libraries provide type-safe query construction, but jOOQ's syntax is closer to SQL, while Querydsl uses a more Java-like approach. jOOQ offers more advanced SQL features and better performance optimization, while Querydsl provides easier integration with JPA and supports a wider range of databases. The choice between the two depends on specific project requirements and developer preferences.
The Jdbi library provides convenient, idiomatic access to relational databases in Java and other JVM technologies such as Kotlin, Clojure or Scala.
Pros of jdbi
- Lightweight and simple to use, with a focus on ease of integration
- Supports both fluent and SQL-based query styles
- Provides powerful result mapping capabilities
Cons of jdbi
- Less comprehensive SQL dialect support compared to jOOQ
- Limited code generation features
- Smaller community and ecosystem
Code Comparison
jdbi example:
String sql = "SELECT * FROM users WHERE name = :name";
List<User> users = handle.createQuery(sql)
.bind("name", "Alice")
.mapTo(User.class)
.list();
jOOQ example:
List<User> users = dsl.selectFrom(USERS)
.where(USERS.NAME.eq("Alice"))
.fetchInto(User.class);
Both jOOQ and jdbi are Java database libraries that aim to simplify database access and query execution. jOOQ offers a more comprehensive SQL dialect support and advanced code generation features, while jdbi focuses on simplicity and ease of use.
jOOQ provides a type-safe DSL for writing SQL queries, which can catch errors at compile-time. It also offers better support for complex queries and database-specific features. On the other hand, jdbi is more lightweight and may be easier to integrate into existing projects, especially those already using raw SQL.
The choice between the two depends on project requirements, team expertise, and the complexity of database operations needed.
requery - modern SQL based query & persistence for Java / Kotlin / Android
Pros of requery
- Lightweight and easy to set up, with minimal configuration required
- Supports both SQL and NoSQL databases, offering greater flexibility
- Provides built-in RxJava support for reactive programming
Cons of requery
- Less mature and smaller community compared to jOOQ
- Limited support for advanced SQL features and database-specific optimizations
- Fewer database dialects supported out of the box
Code Comparison
requery:
@Entity
public class Person {
@Key @Generated int id;
String name;
int age;
}
Person person = new Person();
person.setName("John");
person.setAge(30);
dataStore.insert(person);
jOOQ:
Person person = dsl.newRecord(PERSON);
person.setName("John");
person.setAge(30);
person.store();
Both libraries offer a clean and intuitive API for working with databases, but requery focuses on a more object-oriented approach with annotations, while jOOQ provides a more SQL-like fluent interface. requery's simplicity and flexibility make it attractive for smaller projects or those requiring NoSQL support, while jOOQ's robust SQL support and optimization capabilities make it better suited for complex SQL-based applications.
Convert
designs to code with AI
Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.
Try Visual CopilotREADME
jOOQ
jOOQ is an internal DSL and source code generator, modelling the SQL language as a type safe Java API to help you write better SQL.
Its main features include:
Secondary features include:
- DAOs
- Data export and import
- Data type conversion
- DDL statement support
- DML statement support
- Diagnostics
- Dialect agnosticity for 30+ RDBMS
- Embedded types
- Formatting and pretty printing
- Implicit joins
- Kotlin support
- Mapping
- Meta data API
- Mocking API for JDBC
- Model API for use in traversal and replacement
MULTISET
andROW
nested collections and records- Multitenancy
- Parser (and translator)
- Pattern based transformation
- Plain SQL templating
- Policies
- Procedural logic API
- Reactive support via R2DBC
- Readonly columns
- Scala support
- Schema diff
- SQL transformation
- SQL translation
- Stored procedure support
- Transaction API
- UpdatableRecords for simplified CRUD, with opt-in optimistic locking
- And much more
Examples
Typesafe, embedded SQL
jOOQ's main feature is typesafe, embedded SQL, allowing for IDE auto completion of SQL syntax...
... as well as of schema meta data:
This allows for preventing errors of various types, including typos of identifiers:
Or data type mismatches:
The examples are from the code generation blog post.
A more powerful example using nested collections
For many more examples, please have a look at the demo. A key example showing jOOQ's various strengths is from the MULTISET
operator announcement blog post:
Given these target DTOs:
record Actor(String firstName, String lastName) {}
record Film(
String title,
List<Actor> actors,
List<String> categories
) {}
You can now write the following query to fetch films, their nested actors and their nested categorise in a single, type safe query:
List<Film> result =
dsl.select(
FILM.TITLE,
multiset(
select(
FILM.actor().FIRST_NAME,
FILM.actor().LAST_NAME)
.from(FILM.actor())
).as("actors").convertFrom(r -> r.map(mapping(Actor::new))),
multiset(
select(FILM.category().NAME)
.from(FILM.category())
).as("categories").convertFrom(r -> r.map(Record1::value1))
)
.from(FILM)
.orderBy(FILM.TITLE)
.fetch(mapping(Film::new));
The query is completely type safe. Change a column type, name, or the target DTO, and it will stop compiling! Trust only your own eyes:
And here you see the nested result in action from the logs:
How does it work? Look at this annotated example:
List<Film> result =
dsl.select(
FILM.TITLE,
// MULTISET is a standard SQL operator that allows for nesting collections
// directly in SQL. It is either
// - supported natively
// - emulated using SQL/JSON or SQL/XML
multiset(
// Implicit path based joins allow for simpler navigation of foreign
// key relationships.
select(
FILM.actor().FIRST_NAME,
FILM.actor().LAST_NAME)
// Implicit correlation to outer queries allows for avoiding repetitive
// writing of predicates.
.from(FILM.actor())
// Ad-hoc conversion allows for mapping structural Record2<String, String>
// types to your custom DTO using constructor references
).as("actors").convertFrom(r -> r.map(mapping(Actor::new))),
multiset(
select(FILM.category().NAME)
.from(FILM.category())
).as("categories").convertFrom(r -> r.map(Record1::value1))
)
.from(FILM)
.orderBy(FILM.TITLE)
.fetch(mapping(Film::new));
The generated SQL query might look like this, in PostgreSQL:
select
film.title,
(
select coalesce(
jsonb_agg(jsonb_build_object(
'first_name', t.first_name,
'last_name', t.last_name
)),
jsonb_build_array()
)
from (
select
alias_78509018.first_name,
alias_78509018.last_name
from (
film_actor
join actor as alias_78509018
on film_actor.actor_id = alias_78509018.actor_id
)
where film_actor.film_id = film.film_id
) as t
) as actors,
(
select coalesce(
jsonb_agg(jsonb_build_object('name', t.name)),
jsonb_build_array()
)
from (
select alias_130639425.name
from (
film_category
join category as alias_130639425
on film_category.category_id = alias_130639425.category_id
)
where film_category.film_id = film.film_id
) as t
) as categories
from film
order by film.title
This particular example is explained more in detail in the MULTISET
operator announcement blog post. For many more examples, please have a look at the demo.
Top Related Projects
MyBatis SQL mapper framework for Java
Hibernate's core Object/Relational Mapping functionality
Unified Queries for Java
The Jdbi library provides convenient, idiomatic access to relational databases in Java and other JVM technologies such as Kotlin, Clojure or Scala.
requery - modern SQL based query & persistence for Java / Kotlin / Android
Convert
designs to code with AI
Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.
Try Visual Copilot