Convert Figma logo to code with AI

jOOQ logojOOQ

jOOQ is the best way to write SQL in Java

6,370
1,216
6,370
2,064

Top Related Projects

20,053

MyBatis SQL mapper framework for Java

Hibernate's core Object/Relational Mapping functionality

Unified Queries for Java

2,023

The Jdbi library provides convenient, idiomatic access to relational databases in Java and other JVM technologies such as Kotlin, Clojure or Scala.

3,130

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

  1. Simple SELECT query:
Result<Record> result = create.select()
                              .from(AUTHOR)
                              .where(AUTHOR.FIRST_NAME.eq("John"))
                              .fetch();
  1. JOIN operation:
Result<Record> result = create.select(AUTHOR.NAME, BOOK.TITLE)
                              .from(AUTHOR)
                              .join(BOOK).on(AUTHOR.ID.eq(BOOK.AUTHOR_ID))
                              .fetch();
  1. INSERT with returning clause:
AuthorRecord author = create.insertInto(AUTHOR)
                            .set(AUTHOR.FIRST_NAME, "John")
                            .set(AUTHOR.LAST_NAME, "Doe")
                            .returning(AUTHOR.ID)
                            .fetchOne();
  1. 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

  1. Add jOOQ dependency to your project (Maven example):
<dependency>
    <groupId>org.jooq</groupId>
    <artifactId>jooq</artifactId>
    <version>3.17.6</version>
</dependency>
  1. Configure your database connection:
Connection conn = DriverManager.getConnection("jdbc:postgresql:database", "user", "password");
DSLContext create = DSL.using(conn, SQLDialect.POSTGRES);
  1. 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

20,053

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.

2,023

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.

3,130

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 Figma logo designs to code with AI

Visual Copilot

Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.

Try Visual Copilot

README

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:

Examples

Typesafe, embedded SQL

jOOQ's main feature is typesafe, embedded SQL, allowing for IDE auto completion of SQL syntax...

image

... as well as of schema meta data:

image

This allows for preventing errors of various types, including typos of identifiers:

image

Or data type mismatches:

image

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:

multiset

And here you see the nested result in action from the logs:

execute

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.