Discover millions of ebooks, audiobooks, and so much more with a free trial

Only $11.99/month after trial. Cancel anytime.

jOOQ Masterclass: A practical guide for Java developers to write SQL queries for complex database interactions
jOOQ Masterclass: A practical guide for Java developers to write SQL queries for complex database interactions
jOOQ Masterclass: A practical guide for Java developers to write SQL queries for complex database interactions
Ebook1,459 pages11 hours

jOOQ Masterclass: A practical guide for Java developers to write SQL queries for complex database interactions

Rating: 0 out of 5 stars

()

Read preview

About this ebook

jOOQ is an excellent query builder framework that allows you to emulate database-specific SQL statements using a fluent, intuitive, and flexible DSL API. jOOQ is fully capable of handling the most complex SQL in more than 30 different database dialects.
jOOQ Masterclass covers jOOQ from beginner to expert level using examples (for MySQL, PostgreSQL, SQL Server, and Oracle) that show you how jOOQ is a mature and complete solution for implementing the persistence layer. You’ll learn how to use jOOQ in Spring Boot apps as a replacement for SpringTemplate and Spring Data JPA. Next, you’ll unleash jOOQ type-safe queries and CRUD operations via jOOQ’s records, converters, bindings, types, mappers, multi-tenancy, logging, and testing. Later, the book shows you how to use jOOQ to exploit powerful SQL features such as UDTs, embeddable types, embedded keys, and more. As you progress, you’ll cover trending topics such as identifiers, batching, lazy loading, pagination, and HTTP long conversations. For implementation purposes, the jOOQ examples explained in this book are written in the Spring Boot context for Maven/Gradle against MySQL, Postgres, SQL Server, and Oracle.
By the end of this book, you’ll be a jOOQ power user capable of integrating jOOQ in the most modern and sophisticated apps including enterprise apps, microservices, and so on.

LanguageEnglish
Release dateAug 19, 2022
ISBN9781800564862
jOOQ Masterclass: A practical guide for Java developers to write SQL queries for complex database interactions

Read more from Anghel Leonard

Related to jOOQ Masterclass

Related ebooks

Programming For You

View More

Related articles

Reviews for jOOQ Masterclass

Rating: 0 out of 5 stars
0 ratings

0 ratings0 reviews

What did you think?

Tap to rate

Review must be at least 10 words

    Book preview

    jOOQ Masterclass - Anghel Leonard

    Cover.png

    BIRMINGHAM—MUMBAI

    jOOQ Masterclass

    Copyright © 2022 Packt Publishing

    All rights reserved. No part of this book may be reproduced, stored in a retrieval system, or transmitted in any form or by any means, without the prior written permission of the publisher, except in the case of brief quotations embedded in critical articles or reviews.

    Every effort has been made in the preparation of this book to ensure the accuracy of the information presented. However, the information contained in this book is sold without warranty, either express or implied. Neither the author, nor Packt Publishing or its dealers and distributors, will be held liable for any damages caused or alleged to have been caused directly or indirectly by this book.

    Packt Publishing has endeavored to provide trademark information about all of the companies and products mentioned in this book by the appropriate use of capitals. However, Packt Publishing cannot guarantee the accuracy of this information.

    Assistant Group Product Manager: Alok Dhuri

    Senior Editor: Kinnari Chohan

    Technical Editor: Maran Fernandes

    Copy Editor: Safis Editing

    Project Coordinator: Manisha Singh

    Proofreader: Safis Editing

    Indexer: Tejal Daruwale Soni

    Production Designer: Aparna Bhagat

    Marketing Coordinator: Sonakshi Bubbar

    First published: July 2022

    Production reference: 2110822

    Published by Packt Publishing Ltd.

    Livery Place

    35 Livery Street

    Birmingham

    B3 2PB, UK.

    ISBN 978-1-80056-689-7

    www.packt.com

    Foreword

    It has been a great pleasure reviewing Anghel's book over the past year.

    Anghel is very knowledgeable about databases in general, as well as SQL specifically and the various popular persistence technologies in the Java ecosystem. This shows in his examples, which are suitable both for beginners and for SQL gurus, who will use at least two window functions in every query.

    jOOQ Masterclass is very well structured, both for jOOQ rookies who wish to learn about how to put jOOQ to best use and advanced jOOQ users who wish to have a reference for almost any use case that jOOQ supports. Anghel has a vast number of examples, which are both intuitive and powerful.

    With this book at your disposal, your next jOOQ application will be a breeze.

    – Lukas Eder, Founder and CEO of Data Geekery, the company behind jOOQ

    Contributors

    About the author

    Anghel Leonard is a chief technology strategist and independent consultant with 20+ years of experience in the Java ecosystem. In his daily work, he is focused on architecting and developing Java-distributed applications that empower robust architectures, clean code, and high performance. He is also passionate about coaching, mentoring, and technical leadership. He is the author of several books, videos, and dozens of articles related to Java technologies.

    I want to thank Lukas Eder who has guided me while writing this book and who has always been quick to answer my questions, suggestions, and so on.

    About the reviewers

    Matthew Cachia has a bachelor's degree in computer science and has been working in the payments space for more than 14 years. He is currently the technical architect of Weavr.io.

    He is into static-type languages – most notably, Java, Scala, and Kotlin. He has become increasingly fascinated by compilers, transpilers, and languages overall – a field he regrets not picking up when reading his degree.

    In his free time, he likes playing role-playing games and spending time with his family – Georgiana, Thomas, and Alex.

    Lukas Eder is the founder and CEO of Data Geekery, the company behind jOOQ.

    Table of Contents

    Preface

    Part 1: jOOQ as a Query Builder, SQL Executor, and Code Generator

    Chapter 1: Starting jOOQ and Spring Boot

    Technical requirements

    Starting jOOQ and Spring Boot instantly

    Adding the jOOQ open source edition

    Adding a jOOQ free trial (commercial edition)

    Injecting DSLContext into Spring Boot repositories

    Using the jOOQ query DSL API to generate valid SQL

    Executing the generated SQL and mapping the result set

    Summary

    Chapter 2: Customizing the jOOQ Level of Involvement

    Technical requirements

    Understanding what type-safe queries are

    Generating a jOOQ Java-based schema

    Code generation from a database directly

    Code generation from SQL files (DDL)

    Code generation from entities (JPA)

    Writing queries using a Java-based schema

    jOOQ versus JPA Criteria versus QueryDSL

    Configuring jOOQ to generate POJOs

    Configuring jOOQ to generate DAOs

    Configuring jOOQ to generate interfaces

    Tackling programmatic configuration

    Introducing jOOQ settings

    Summary

    Part 2: jOOQ and Queries

    Chapter 3: jOOQ Core Concepts

    Technical requirements

    Hooking jOOQ results (Result) and records (Record)

    Fetching Result via plain SQL

    Fetching Result via select()

    Fetching Result via select() and join()

    Fetching Result via selectFrom()

    Fetching Result via ad hoc selects

    Fetching Result via UDTs

    Exploring jOOQ query types

    Understanding the jOOQ fluent API

    Writing fluent queries

    Creating DSLContext

    Using Lambdas and streams

    Fluent programmatic configuration

    Highlighting that jOOQ emphasizes SQL syntax correctness

    Casting, coercing, and collating

    Casting

    Coercing

    Collation

    Binding values (parameters)

    Indexed parameters

    Named parameters

    Inline parameters

    Rendering a query with different types of parameter placeholders

    Extracting jOOQ parameters from the query

    Extracting binding values

    Setting new bind values

    Summary

    Chapter 4: Building a DAO Layer (Evolving the Generated DAO Layer)

    Technical requirements

    Hooking the DAO layer

    Shaping the DAO design pattern and using jOOQ

    Shaping the generic DAO design pattern and using jOOQ

    Extending the jOOQ built-in DAO

    Summary

    Chapter 5: Tackling Different Kinds of SELECT, INSERT, UPDATE, DELETE, and MERGE

    Technical requirements

    Expressing SELECT statements

    Expressing commonly used projections

    Expressing SELECT to fetch only the needed data

    Expressing SELECT subqueries (subselects)

    Expressing scalar subqueries

    Expressing correlated subqueries

    Expressing row expressions

    Expressing the UNION and UNION ALL operators

    Expressing the INTERSECT (ALL) and EXCEPT (ALL) operators

    Expressing distinctness

    Expressing INSERT statements

    Expressing UPDATE statements

    Expressing DELETE statements

    Expressing MERGE statements

    Summary

    Chapter 6: Tackling Different Kinds of JOINs

    Technical requirements

    Practicing the most popular types of JOINs

    CROSS JOIN

    INNER JOIN

    OUTER JOIN

    PARTITIONED OUTER JOIN

    The SQL USING and jOOQ onKey() shortcuts

    SQL JOIN … USING

    jOOQ onKey()

    Practicing more types of JOINs

    Implicit and Self Join

    NATURAL JOIN

    STRAIGHT JOIN

    Semi and Anti Joins

    LATERAL/APPLY Join

    Summary

    Chapter 7: Types, Converters, and Bindings

    Technical requirements

    Default data type conversion

    Custom data types and type conversion

    Writing an org.jooq.Converter interface

    Hooking forced types for converters

    JSON converters

    UDT converters

    Custom data types and type binding

    Understanding what's happening without Binding

    Manipulating enums

    Writing enum converters

    Data type rewrites

    Handling embeddable types

    Replacing fields

    Converting embeddable types

    Embedded domains

    Summary

    Chapter 8: Fetching and Mapping

    Technical requirements

    Simple fetching/mapping

    Collector methods

    Mapping methods

    Simple fetching/mapping continues

    Fetching one record, a single record, or any record

    Using fetchOne()

    Using fetchSingle()

    Using fetchAny()

    Fetching arrays, lists, sets, and maps

    Fetching arrays

    Fetching lists and sets

    Fetching maps

    Fetching groups

    Fetching via JDBC ResultSet

    Fetching multiple result sets

    Fetching relationships

    Hooking POJOs

    Types of POJOs

    jOOQ record mappers

    The mighty SQL/JSON and SQL/XML support

    Handling SQL/JSON support

    Handling SQL/XML support

    Nested collections via the astonishing MULTISET

    Mapping MULTISET to DTO

    The MULTISET_AGG() function

    Comparing MULTISETs

    Lazy fetching

    Lazy featching via fetchStream()/fetchStreamInto()

    Asynchronous fetching

    Reactive fetching

    Summary

    Part 3: jOOQ and More Queries

    Chapter 9: CRUD, Transactions, and Locking

    Technical requirements

    CRUD

    Attaching/detaching updatable records

    What's an original (updatable) record?

    Marking (updatable) records as changed/unchanged

    Resetting an (updatable) record

    Refreshing an updatable record

    Inserting updatable records

    Updating updatable records (this sounds funny)

    Deleting updatable records

    Merging updatable records

    Storing updatable records

    Using updatable records in HTTP conversations

    Navigating (updatable) records

    Transactions

    SpringTransactionProvider

    ThreadLocalTransactionProvider

    jOOQ asynchronous transactions

    @Transactional versus the jOOQ transaction API

    Hooking reactive transactions

    Locking

    Optimistic locking overview

    jOOQ optimistic locking

    Pessimistic locking overview

    jOOQ pessimistic locking

    Deadlocks

    Summary

    Chapter 10: Exporting, Batching, Bulking, and Loading

    Technical requirements

    Exporting data

    Exporting as text

    Exporting JSON

    Export XML

    Exporting HTML

    Exporting CSV

    Exporting a chart

    Exporting INSERT statements

    Batching

    Batching via DSLContext.batch()

    Batching records

    Batched connection

    Bulking

    Loading (the Loader API)

    The Loader API syntax

    Examples of using the Loader API

    Summary

    Chapter 11: jOOQ Keys

    Technical requirements

    Fetching the database-generated primary key

    Suppressing a primary key return on updatable records

    Updating a primary key of an updatable record

    Using database sequences

    Inserting a SQL Server IDENTITY

    Fetching the Oracle ROWID pseudo-column

    Comparing composite primary keys

    Working with embedded keys

    Working with jOOQ synthetic objects

    Synthetic primary/foreign keys

    Synthetic unique keys

    Synthetic identities

    Hooking computed columns

    Overriding primary keys

    Summary

    Chapter 12: Pagination and Dynamic Queries

    Technical requirements

    Offset and keyset pagination

    Index scanning in offset and keyset

    jOOQ offset pagination

    jOOQ keyset pagination

    The jOOQ SEEK clause

    Implementing infinite scroll

    Paginating JOINs via DENSE_RANK()

    Paginating database views via ROW_NUMBER()

    Writing dynamic queries

    Using the ternary operator

    Using jOOQ comparators

    Using SelectQuery, InsertQuery, UpdateQuery, and DeleteQuery

    Writing generic dynamic queries

    Writing functional dynamic queries

    Infinite scrolling and dynamic filters

    Summary

    Part 4: jOOQ and Advanced SQL

    Chapter 13: Exploiting SQL Functions

    Technical requirements

    Regular functions

    SQL functions for dealing with NULLs

    Numeric functions

    String functions

    Aggregate functions

    Window functions

    ROWS

    GROUPS

    RANGE

    BETWEEN start_of_frame AND end_of_frame

    frame_exclusion

    The QUALIFY clause

    Working with ROW_NUMBER()

    Working with RANK()

    Working with DENSE_RANK()

    Working with PERCENT_RANK()

    Working with CUME_DIST()

    Working with LEAD()/LAG()

    Working with NTILE()

    Working with FIRST_VALUE() and LAST_VALUE()

    Working with RATIO_TO_REPORT()

    Aggregates as window functions

    Aggregate functions and ORDER BY

    FOO_AGG()

    COLLECT()

    GROUP_CONCAT()

    Oracle's KEEP() clause

    Ordered set aggregate functions (WITHIN GROUP)

    Hypothetical set functions

    Inverse distribution functions

    LISTAGG()

    Grouping, filtering, distinctness, and functions

    Grouping

    Filtering

    Distinctness

    Grouping sets

    Summary

    Chapter 14: Derived Tables, CTEs, and Views

    Technical requirements

    Derived tables

    Extracting/declaring a derived table in a local variable

    Exploring Common Table Expressions (CTEs) in jOOQ

    Regular CTEs

    Recursive CTEs

    CTEs and window functions

    Using CTEs to generate data

    Dynamic CTEs

    Expressing a query via a derived table, a temporary table, and a CTE

    Handling views in jOOQ

    Updatable and read-only views

    Types of views (unofficial categorization)

    Some examples of views

    Summary

    Chapter 15: Calling and Creating Stored Functions and Procedures

    Technical requirements

    Calling stored functions/procedures from jOOQ

    Stored functions

    Stored procedures

    Stored procedures and output parameters

    Stored procedures fetching a single result set

    Stored procedures with a single cursor

    Stored procedures fetching multiple result sets

    Stored procedures with multiple cursors

    Calling stored procedures via the CALL statement

    jOOQ and creating stored functions/procedures

    Creating stored functions

    Creating stored procedures

    Summary

    Chapter 16: Tackling Aliases and SQL Templating

    Technical requirements

    Expressing SQL aliases in jOOQ

    Expressing simple aliased tables and columns

    Aliases and JOINs

    Aliases and GROUP BY/ORDER BY

    Aliases and bad assumptions

    Aliases and typos

    Aliases and derived tables

    Derived column list

    Aliases and the CASE expression

    Aliases and IS NOT NULL

    Aliases and CTEs

    SQL templating

    Summary

    Chapter 17: Multitenancy in jOOQ

    Technical requirements

    Connecting to a separate database per role/login via the RenderMapping API

    Connecting to a separate database per role/login via a connection switch

    Generating code for two schemas of the same vendor

    Generating code for two schemas of different vendors

    Summary

    Part 5: Fine-tuning jOOQ, Logging, and Testing

    Chapter 18: jOOQ SPI (Providers and Listeners)

    Technical requirements

    jOOQ settings

    jOOQ Configuration

    jOOQ providers

    TransactionProvider

    ConverterProvider

    RecordMapperProvider

    jOOQ listeners

    ExecuteListener

    jOOQ SQL parser and ParseListener

    RecordListener

    DiagnosticsListener

    TransactionListener

    VisitListener

    Altering the jOOQ code generation process

    Implementing a custom generator

    Writing a custom generator strategy

    Summary

    Chapter 19: Logging and Testing

    Technical requirements

    jOOQ logging

    jOOQ logging in Spring Boot – default zero-configuration logging

    jOOQ logging with Logback/log4j2

    Turn off jOOQ logging

    Customizing result set logging

    Customizing binding parameters logging

    Customizing logging invocation order

    Wrapping jOOQ logging into custom text

    Filtering jOOQ logging

    jOOQ testing

    Mocking the jOOQ API

    Writing integration tests

    Testing R2DBC

    Summary

    Other Books You May Enjoy

    Preface

    The last decade has constantly changed how we think and write applications including the persistence layer, which must face new challenges such as working in microservice architectures and cloud environments. Flexibility, versatility, dialect agnostic, rock-solid SQL support, small learning curve, and high performance are just a few of the attributes that makes jOOQ the most appealing persistence technology for modern applications.

    Being part of the modern technology stack, jOOQ is the new persistence trend that respects all standards of a mature, robust, and well-documented technology. This book covers jOOQ in detail, so it prepares you to become a jOOQ power-user and an upgraded version of yourself ready to handle the future of the persistence layer. Don't think of jOOQ as just another piece of technology; think of it as part of your mindset, your straightforward road to exploiting SQL instead of abstracting it, and your approach to doing things right in your organization.

    Who this book is for

    This book is for Java developers who write applications that interact with databases via SQL. No prior experience with jOOQ is assumed.

    What this book covers

    Chapter 1, Starting jOOQ and Spring Boot, shows how to create a kickoff application that involves jOOQ and Spring Boot in Java/Kotlin under Maven/Gradle.

    Chapter 2, Customizing the jOOQ Level of Involvement, covers the configurations (declarative and programmatic) needed for employing jOOQ as a type-safe query builder and executor. Moreover, we set up jOOQ to generate POJOs and DAOs on our behalf. We use Java/Kotlin under Maven/Gradle.

    Chapter 3, jOOQ Core Concepts, discusses jOOQ core concepts such as fluent API, SQL syntax correctness, emulating missing syntax/logic, jOOQ result set, jOOQ records, type safety, CRUD binding, and inlining parameters.

    Chapter 4, Building a DAO Layer (Evolving the Generated DAO Layer), shows how implementing a DAO layer can be done in several ways/templates. We tackle an approach for evolving the DAO layer generated by jOOQ.

    Chapter 5, Tackling Different Kinds of SELECT, INSERT, UPDATE, DELETE, and MERGE Statements, covers different kinds of SELECT, INSERT, UPDATE, DELETE, and MERGE queries. For example, we cover nested SELECT, INSERT...DEFAULT VALUES, INSERT...SET queries, and so on.

    Chapter 6, Tackling Different Kinds of JOIN Statements, tackles different kinds of JOIN. jOOQ excels on standard and non-standard JOIN. We cover INNER, LEFT, RIGHT, …, CROSS, NATURAL, and LATERAL JOIN.

    Chapter 7, Types, Converters, and Bindings, covers the custom data types, conversion, and binding.

    Chapter 8, Fetching and Mapping, being one of the most comprehensive chapters, covers a wide range of jOOQ fetching and mapping techniques, including JSON/SQL, XML/SQL, and MULTISET features.

    Chapter 9, CRUD, Transactions, and Locking, covers jOOQ CRUD support next to Spring/jOOQ transactions and optimistic/pessimistic locking.

    Chapter 10, Exporting, Batching, Bulking, and Loading, covers batching, bulking, and loading files into the database via jOOQ. We will do single-thread and multi-thread batching.

    Chapter 11, jOOQ Keys, tackles the different kinds of identifiers (auto-generated, natural IDs, and composite IDs) from the jOOQ perspective.

    Chapter 12, Pagination and Dynamic Queries, covers pagination and building dynamic queries. Mainly, all jOOQ queries are dynamic, but in this chapter, we will highlight this, and we will write several filters by gluing and reusing different jOOQ artifacts.

    Chapter 13, Exploiting SQL Functions, covers window functions (probably the most powerful SQL feature) in the jOOQ context.

    Chapter 14, Derived Tables, CTEs, and Views, covers derived tables and recursive Common Table Expressions (CTEs) in the jOOQ context.

    Chapter 15, Calling and Creating Stored Functions and Procedures, covers stored procedures and functions in the jOOQ context. This is one of the most powerful and popular jOOQ features.

    Chapter 16, Tackling Aliases and SQL Templating, covers aliases and SQL templating. As you'll see, this chapter contains a must-have set of knowledge that will help you to avoid common related pitfalls.

    Chapter 17, Multitenancy in jOOQ, covers different aspects of multi-tenancy/partitioning.

    Chapter 18, jOOQ SPI (Providers and Listeners), covers jOOQ providers and listeners. Using these kinds of artifacts, we can interfere with the default behavior of jOOQ.

    Chapter 19, Logging and Testing, covers jOOQ logging and testing.

    To get the most out of this book

    To get the most out of this book, you'll need to know the Java language and be familiar with one of the following database technologies:

    Refer to this link for additional installation instructions and information you need to set things up: https://github.com/PacktPublishing/jOOQ-Masterclass/tree/master/db.

    If you are using the digital version of this book, we advise you to type the code yourself or access the code from the book's GitHub repository (a link is available in the next section). Doing so will help you avoid any potential errors related to the copying and pasting of code.

    Download the example code files

    You can download the example code files for this book from GitHub at https://github.com/PacktPublishing/jOOQ-Masterclass. If there's an update to the code, it will be updated in the GitHub repository.

    We also have other code bundles from our rich catalog of books and videos available at https://github.com/PacktPublishing/. Check them out!

    Download the color images

    We also provide a PDF file that has color images of the screenshots and diagrams used in this book. You can download it here: https://packt.link/a1q9L.

    Conventions used

    There are a number of text conventions used throughout this book.

    Code in text: Indicates code words in text, database table names, folder names, filenames, file extensions, pathnames, dummy URLs, user input, and Twitter handles. Here is an example: For instance, the next snippet of code relies on the fetchInto() flavor.

    A block of code is set as follows:

    // 'query' is the ResultQuery object

    List result = query.fetchInto(Office.class);

    When we wish to draw your attention to a particular part of a code block, the relevant lines or items are set in bold:

    public List findOfficesInTerritory(

                                        String territory) {

      List result = ctx.selectFrom(table(office))

        .where(field(territory).eq(territory))

        .fetchInto(Office.class);

      return result;

    }

    Any command-line input or output is written as follows:

      product_line>Vintage Cars

      product_id>80

      product_name>1936 Mercedes Benz ...

    ...

    Tips or Important Notes

    Appear like this.

    Get in touch

    Feedback from our readers is always welcome.

    General feedback: If you have questions about any aspect of this book, email us at [email protected] and mention the book title in the subject of your message.

    Errata: Although we have taken every care to ensure the accuracy of our content, mistakes do happen. If you have found a mistake in this book, we would be grateful if you would report this to us. Please visit www.packtpub.com/support/errata and fill in the form.

    Piracy: If you come across any illegal copies of our works in any form on the internet, we would be grateful if you would provide us with the location address or website name. Please contact us at [email protected] with a link to the material.

    If you are interested in becoming an author: If there is a topic that you have expertise in and you are interested in either writing or contributing to a book, please visit authors.packtpub.com.

    Share Your Thoughts

    Once you've read jOOQ Masterclass, we'd love to hear your thoughts! Please click here to go straight to the Amazon review page for this book and share your feedback.

    Your review is important to us and the tech community and will help us make sure we're delivering excellent quality content.

    Part 1: jOOQ as a Query Builder, SQL Executor, and Code Generator

    By the end of this part, you will know how to take advantage of the aforementioned three terms in the title in different kickoff applications. You will see how jOOQ can be used as a companion or as a total replacement for your current persistence technology (most probably, an ORM).

    This part contains the following chapters:

    Chapter 1, Starting jOOQ and Spring Boot

    Chapter 2, Customizing the jOOQ Level of Involvement

    Chapter 1: Starting jOOQ and Spring Boot

    This chapter is a practical guide to start working with jOOQ (open source and free trial commercial) in Spring Boot applications. For convenience, let's assume that we have a Spring Boot stub application and plan to implement the persistence layer via jOOQ.

    The goal of this chapter is to highlight the fact that setting the environment for generating and executing SQL queries via jOOQ in a Spring Boot application is a job that can be accomplished almost instantly in any of the Java/Kotlin and Maven/Gradle combinations. Besides that, this is a good opportunity to have your first taste of the jOOQ DSL-fluent API and to get your first impressions.

    The topics of this chapter include the following:

    Starting jOOQ and Spring Boot instantly

    Using the jOOQ query DSL API to generate a valid SQL statement

    Executing the generated SQL and mapping the result set to a POJO

    Let's get started!

    Technical requirements

    The code for this chapter can be found on GitHub at https://github.com/PacktPublishing/jOOQ-Masterclass/tree/master/Chapter01.

    Starting jOOQ and Spring Boot instantly

    Spring Boot provides support for jOOQ, and this aspect is introduced in the Spring Boot official documentation under the Using jOOQ section. Having built-in support for jOOQ makes our mission easier, since, among other things, Spring Boot is capable of dealing with aspects that involve useful default configurations and settings.

    Consider having a Spring Boot stub application that will run against MySQL and Oracle, and let's try to add jOOQ to this context. The goal is to use jOOQ as a SQL builder for constructing valid SQL statements and as a SQL executor that maps the result set to a POJO.

    Adding the jOOQ open source edition

    Adding the jOOQ open source edition into a Spring Boot application is quite straightforward.

    Adding the jOOQ open source edition via Maven

    From the Maven perspective, adding the jOOQ open source edition into a Spring Boot application starts from the pom.xml file. The jOOQ open source edition dependency is available at Maven Central (https://mvnrepository.com/artifact/org.jooq/jooq) and can be added like this:

      org.jooq

      jooq

      ...

    Alternatively, if you prefer a Spring Boot starter, then rely on this one:

      org.springframework.boot

      spring-boot-starter-jooq

    If you are a fan of Spring Initializr (https://start.spring.io/), then just select the jOOQ dependency from the corresponding list of dependencies.

    That's all! Note that is optional. If is omitted, then Spring Boot will properly choose the jOOQ version compatible with the Spring Boot version used by the application. Nevertheless, whenever you want to try a different jOOQ version, you can simply add explicitly. At this point, the jOOQ open source edition is ready to be used to start developing the persistence layer of an application.

    Adding the jOOQ open source edition via Gradle

    From the Gradle perspective, adding the jOOQ open source edition into a Spring Boot application can be accomplished via a plugin named gradle-jooq-plugin (https://github.com/etiennestuder/gradle-jooq-plugin/). This can be added to your build.gradle, as follows:

    plugins {

      id 'nu.studer.jooq' version ...

    }

    Of course, if you rely on Spring Initializr (https://start.spring.io/), then just select a Gradle project, add the jOOQ dependency from the corresponding list of dependencies, and once the project is generated, add the gradle-jooq-plugin plugin. As you'll see in the next chapter, using gradle-jooq-plugin is quite convenient for configuring the jOOQ Code Generator.

    Adding a jOOQ free trial (commercial edition)

    Adding a free trial commercial edition of jOOQ (jOOQ Express, Professional, and Enterprise editions) to a Spring Boot project (overall, in any other type of project) requires a few preliminary steps. Mainly, these steps are needed because the jOOQ free trial commercial distributions are not available on Maven Central, so you have to manually download the one that you need from the jOOQ download page (https://www.jooq.org/download/). For instance, you can choose the most popular one, the jOOQ Professional distribution, which comes packaged as a ZIP archive. Once you have unzipped it, you can install it locally via the maven-install command. You can find these steps exemplified in a short movie in the bundled code (Install_jOOQ_Trial.mp4).

    For Maven applications, we use the jOOQ free trial identified as org.jooq.trial (for Java 17) or org.jooq.trial-java-{version}. When this book was written, the version placeholder could be 8 or 11, but don't hesitate to check for the latest updates. We prefer the former, so in pom.xml, we have the following:

      org.jooq.trial-java-8

      jooq

      ...

    For Java/Gradle, you can do it, as shown in the following example, via gradle-jooq-plugin:

    jooq {

      version = '...'

      edition = nu.studer.gradle.jooq.JooqEdition.TRIAL_JAVA_8

    }

    For Kotlin/Gradle, you can do it like this:

    jooq {

      version.set(...)

      edition.set(nu.studer.gradle.jooq.JooqEdition.TRIAL_JAVA_8)

    }

    In this book, we will use jOOQ open source in applications that involve MySQL and PostgreSQL, and jOOQ free trial in applications that involve SQL Server and Oracle. These two database vendors are not supported in jOOQ open source.

    If you're interested in adding jOOQ in a Quarkus project then consider this resource: https://github.com/quarkiverse/quarkus-jooq

    Injecting DSLContext into Spring Boot repositories

    One of the most important interfaces of jOOQ is org.jooq.DSLContext. This interface represents the starting point of using jOOQ, and its main goal is to configure the behavior of jOOQ when executing queries. The default implementation of this interface is named DefaultDSLContext. Among the approaches, DSLContext can be created via an org.jooq.Configuration object, directly from a JDBC connection (java.sql.Connection), a data source (javax.sql.DataSource), and a dialect needed for translating the Java API query representation, written via jOOQ into a database-specific SQL query (org.jooq.SQLDialect).

    Important Note

    For java.sql.Connection, jOOQ will give you full control of the connection life cycle (for example, you are responsible for closing this connection). On the other hand, connections acquired via javax.sql.DataSource will be automatically closed after query execution by jOOQ. Spring Boot loves data sources, therefore the connection management is already handled (acquire and return connection from/to the connection pool, transaction begin/commit/rollback, and so on).

    All jOOQ objects, including DSLContext, are created from org.jooq.impl.DSL. For creating a DSLContext, the DSL class exposes a static method named using(), which comes in several flavors. Of these, the most notable are listed next:

    // Create DSLContext from a pre-existing configuration

    DSLContext ctx = DSL.using(configuration);

    // Create DSLContext from ad-hoc arguments

    DSLContext ctx = DSL.using(connection, dialect);

    For example, connecting to the MySQL classicmodels database can be done as follows:

    try (Connection conn = DriverManager.getConnection(

        jdbc:mysql://localhost:3306/classicmodels,

        root, root)) {

      DSLContext ctx =

        DSL.using(conn, SQLDialect.MYSQL);

      ...

    } catch (Exception e) {

      ...

    }

    Alternatively, you can connect via a data source:

    DSLContext ctx = DSL.using(dataSource, dialect);

    For example, connecting to the MySQL classicmodels database via a data source can be done as follows:

    DSLContext getContext() {

      MysqlDataSource dataSource = new MysqlDataSource();

      dataSource.setServerName(localhost);

      dataSource.setDatabaseName(classicmodels);

      dataSource.setPortNumber(3306);

      dataSource.setUser(props.getProperty(root);

      dataSource.setPassword(props.getProperty(root);

      return DSL.using(dataSource, SQLDialect.MYSQL);

    }

    But Spring Boot is capable of automatically preparing a ready-to-inject DSLContext based on our database settings. For example, Spring Boot can prepare DSLContext based on the MySQL database settings specified in application.properties:

    spring.datasource.driverClassName=com.mysql.cj.jdbc.Driver

    spring.datasource.url=jdbc:mysql://localhost:3306/

                     classicmodels?createDatabaseIfNotExist=true

    spring.datasource.username=root

    spring.datasource.password=root

    spring.jooq.sql-dialect=MYSQL

    Once Spring Boot detects the jOOQ presence, it uses the preceding settings to create org.jooq.Configuration, which is used to prepare a ready-to-inject DSLContext.

    Important Note

    While DSLContext has a high degree of configurability and flexibility, Spring Boot performs only the minimum effort to serve a default DSLContext that can be injected and used immediately. As you'll see in this book (but especially in the official jOOQ manual – https://www.jooq.org/doc/latest/manual/), DSLContext has tons of configurations and settings that allow taking control of almost anything that happens with our SQL statements.

    The DSLContext object provided by Spring Boot can be easily injected into our persistence repositories. For instance, the next snippet of code serves such a DSLContext object directly into ClassicModelsRepository:

    @Repository

    public class ClassicModelsRepository {

      private final DSLContext ctx;

      public ClassicModelsRepository(DSLContext ctx) {

        this.ctx = ctx;

      }

      ...

    }

    Don't conclude here that the application needs to keep a reference to DSLContext. That can still be used directly in a local variable, as you saw earlier (which means that you can have as many DSLContext objects as you want). It only means that, in a Spring Boot application, for most common scenarios, it is more convenient to simply inject it as shown previously.

    Internally, jOOQ can use java.sql.Statement or PreparedStatement. By default, and for very good and strong reasons, jOOQ uses PreparedStatement.

    Typically, the DSLContext object is labeled as ctx (used in this book) or dsl. But, other names such as dslContext, jooq, and sql are also good choices. Basically, you name it.

    Okay, so far, so good! At this point, we have access to DSLContext provided out of the box by Spring Boot, based on our settings from application.properties. Next, let's see DSLContext at work via jOOQ's query DSL API.

    Using the jOOQ query DSL API to generate valid SQL

    Using the jOOQ query DSL API to generate valid SQL is a good start for exploring the jOOQ world. Let's take a simple SQL statement, and let's express it via jOOQ. In other words, let's use the jOOQ query DSL API to express a given SQL string query into the jOOQ object-oriented style. Consider the next SQL SELECT written in the MySQL dialect:

    SELECT * FROM `office` WHERE `territory` = ?

    The SQL, SELECT * FROM `office` WHERE `territory` = ?, is written as a plain string. This query can be generated by jOOQ if it is written via the DSL API, as follows (the value of the territory binding variable is supplied by the user):

    ResultQuery query = ctx.selectFrom(table(office))

      .where(field(territory).eq(territory));

    Alternatively, if we want to have the FROM clause closer to SQL look, then we can write it as follows:

    ResultQuery query = ctx.select()

      .from(table(office))                  

      .where(field(territory).eq(territory));

    Most schemas are case-insensitive, but there are databases such as MySQL and PostgreSQL that prefer mostly lowercase, while others such as Oracle prefer mostly uppercase. So, writing the preceding query in Oracle style can be done as follows:

    ResultQuery query = ctx.selectFrom(table(OFFICE))

      .where(field(TERRITORY).eq(territory));

    Alternatively, you can write it via an explicit call of from():

    ResultQuery query = ctx.select()

      .from(table(OFFICE))                  

      .where(field(TERRITORY).eq(territory));

    The jOOQ fluent API is a piece of art that looks like fluent English and, therefore, is quite intuitive to read and write.

    Reading the preceding queries is pure English: select all offices from the OFFICE table where the TERRITORY column is equal to the given value.

    Pretty soon, you'll be amazed at how fast you can write these queries in jOOQ.

    Important Note

    As you'll see in the next chapter, jOOQ can generate a Java-based schema that mirrors the one in the database via a feature named the jOOQ Code Generator. Once this feature is enabled, writing these queries becomes even simpler and cleaner because there will be no need to reference the database schema explicitly, such as the table name or the table columns. Instead, we will reference the Java-based schema.

    And, thanks to the Code Generator feature, jOOQ makes the right choices for us upfront almost everywhere. We no longer need to take care of queries' type-safety and case-sensitivity, or identifiers' quotation and qualification.

    The jOOQ Code Generator atomically boosts the jOOQ capabilities and increases developer productivity. This is why using the jOOQ Code Generator is the recommended way to exploit jOOQ. We will tackle the jOOQ Code Generator in the next chapter.

    Next, the jOOQ query (org.jooq.ResultQuery) must be executed against the database, and the result set will be mapped to a user-defined simple POJO.

    Executing the generated SQL and mapping the result set

    Executing the generated SQL and mapping the result set to a POJO via jOOQ can be done via the fetching methods available in the jOOQ API. For instance, the next snippet of code relies on the fetchInto() flavor:

    public List findOfficesInTerritory(String territory) {

      List result = ctx.selectFrom(table(office))

    .where(field(territory).eq(territory))

        .fetchInto(Office.class);

      return result;

    }

    What happened there?! Where did ResultQuery go? Is this black magic? Obviously not! It's just that jOOQ has immediately fetched results after constructing the query and mapped them to the Office POJO. Yes, the jOOQ's fetchInto(Office.class) or fetch().into(Office.class) would work just fine out of the box. Mainly, jOOQ executes the query and maps the result set to the Office POJO by wrapping and abstracting the JDBC complexity in a more object-oriented way. If we don't want to immediately fetch the results after constructing the query, then we can use the ResultQuery object like this:

    // 'query' is the ResultQuery object

    List result = query.fetchInto(Office.class);

    The Office POJO is available in the code bundled with this book.

    Important Note

    jOOQ has a comprehensive API for fetching and mapping a result set into collections, arrays, maps, and so on. We will detail these aspects later on in Chapter 8, Fetching and Mapping.

    The complete application is named DSLBuildExecuteSQL. Since this can be used as a stub application, you can find it available for Java/Kotlin in combination with Maven/Gradle. These applications (along with, in fact, all the applications in this book) use Flyway for schema migration. As you'll see later, Flyway and jOOQ make a great team.

    So, let's quickly summarize this chapter before moving on to exploit the astonishing jOOQ Code Generator feature.

    Summary

    Note that we barely scratched the surface of jOOQ's capabilities by using it only for generating and executing a simple SQL statement. Nevertheless, we've already highlighted that jOOQ can generate valid SQL against different dialects and can execute and map a result set in a straightforward manner.

    In the next chapter, we learn how to trust jOOQ more by increasing its level of involvement. jOOQ will generate type-safe queries, POJOs, and DAOs on our behalf.

    Chapter 2: Customizing the jOOQ Level of Involvement

    In the previous chapter, we introduced jOOQ in a Spring Boot application and used it for generating and executing a valid non-type-safe SQL statement. In this chapter, we will continue this journey and increase the jOOQ level of involvement via an astonishing feature – the so-called jOOQ Code Generator. In other words, jOOQ will be in control of the persistence layer via a straightforward flow that begins with type-safe queries, continues by generating Plain Old Java Objects (POJOs) used to map the query results as objects, and ends with generating DAOs used to shortcut the most common queries in object-oriented style.

    By the end of this chapter, you'll know how to write type-safe queries, and how to instruct jOOQ to generate POJOs and DAOs that have custom names in Java and Kotlin applications, using Maven and Gradle. We will cover these topics declaratively (for instance, in XML files) and programmatically.

    The following topics will be covered in this chapter:

    Understanding what type-safe queries are

    Generating a jOOQ Java-based schema

    Writing queries using a Java-based schema

    Configuring jOOQ to generate POJOs

    Configuring jOOQ to generate DAOs

    Configuring jOOQ to generate interfaces

    Tackling programmatic configuration

    Introducing jOOQ settings

    Let's start with a brief discussion about type-safe queries.

    Technical requirements

    The code files used in this chapter can be found on GitHub:

    https://github.com/PacktPublishing/jOOQ-Masterclass/tree/master/Chapter02

    Understanding what type-safe queries are

    Generally speaking, what actually is a type-safe API? In short, an API is type-safe if it relies on the type system of a programming language aiming to prevent and report type errors. Specifically, jOOQ enables the compiler to do that via the Code Generator features.

    Working with type-safe SQL is preferable because there is no need to validate every SQL statement via dedicated tests, and it is faster to fix things during coding than while running the application. For example, you can significantly reduce the number of unit tests dedicated to SQL validation and focus on integration tests, which is always a good thing. So, SQL type safety really matters!

    Declaring SQL statements as Java String statements (for example, in JPQL style, which is verified at execution time) doesn't take advantage of type safety. In other words, the compiler cannot guarantee that a SQL statement is valid. This happens in each of the following examples that use different choices for the persistence layer. All these examples compile but fail at runtime.

    Let's see a JdbcTemplate non-type-safe SQL example (with the wrong order of binding values):

    public Manager findManager(Long id, String name) {

      String sql = "SELECT * FROM MANAGER

        WHERE MANAGER_ID=? AND MANAGER_NAME=?";               

      Manager result = jdbcTemplate

        .queryForObject(sql, Manager.class, name, id);

    }

    Here, we have a Spring Data example (name should be String, not int):

    @Query(value = "SELECT c.phone, p.cachingDate FROM Customer c

           INNER JOIN c.payments p WHERE c.customer_name = ?1")

    CustomerPojo fetchCustomerWithCachingDateByName(int name);

    Here is a Spring Data derived query method example (name should be String, not int):

    Customer findByName(int name);

    The following is a jOOQ query builder without the Code Generator example (instead of v, it should be v.getOwnerName()):

    public Customer findCustomer(Voucher v) {        

      ctx.select().from(table(CUSTOMER))                

         .where(field(CUSTOMER.CUSTOMER_NAME).eq(v))...;    

    }

    Here's another jOOQ query builder without the Code Generator example (in our schema, there is no OFFICES table and no CAPACITY column):

    ctx.select()

       .from(table(OFFICES))

       .where(field(OFFICE.CAPACITY).gt(50));

    These are just some simple cases that are easy to spot and fix. Imagine a non-type-safe complex query with a significant number of bindings.

    But, if the jOOQ Code Generator is enabled, then jOOQ will compile the SQL statements against an actual Java-based schema that mirrors a database. This way, jOOQ ensures at least the following:

    The classes and fields that occur in SQL exist, have the expected type, and are mapped to a database.

    There are no type mismatches between the operators and operands.

    The generated query is syntactically valid.

    Important Note

    I said at least because, besides type safety, jOOQ takes care of many other aspects, such as quotations, qualification, and case sensitivity of identifiers. These aspects are not easy to handle across SQL dialects, and thanks to the Code Generator feature, jOOQ makes the right choices for us upfront almost everywhere. As Lukas Eder said: Using jOOQ with the Code Generator is just a little additional setup, but it will help jOOQ to make the right, carefully chosen default choices for so many silly edge cases that are so annoying to handle later on. I can't recommend it enough! :)

    Back to type safety, let's assume that the jOOQ Code Generator has produced the needed artifacts (a suite of classes that mirrors the database tables, columns, routines, views, and so on). In this context, the previous jOOQ examples can be rewritten in a type-safe manner, as follows. Note that none of the following snippets will compile:

    import static jooq.generated.tables.Customer.CUSTOMER;

    ...

    public Customer findCustomer(Voucher v) {        

      ctx.select().from(CUSTOMER)                   

         .where(CUSTOMER.CUSTOMER_NAME.eq(v))...;         

    }

    Besides being less verbose than the original example, this query is type-safe as well. This time, CUSTOMER (which replaced table(CUSTOMER)) is a static instance (shortcut) of the Customer class, representing the customer table. Moreover, CUSTOMER_NAME (which replaced field(CUSTOMER.CUSTOMER_NAME)) is also a static field in the Customer class, representing the customer_name column of the customer table. These Java objects have been generated by the jOOQ Code Generator as part of the Java-based schema. Note how this static instance was nominally imported here – if you find the technique of importing each static artifact cumbersome, then you can simply rely on the neat trick of importing the entire schema as import static jooq.generated.Tables.*.

    The second jOOQ example can be rewritten in a type-safe manner, as follows:

    import static jooq.generated.tables.Office.OFFICE;

    ...

    ctx.select().from(OFFICES).where(OFFICE.CAPACITY.gt(50));

    The following figure is a screenshot from the IDE, showing that the compiler complains about the type safety of this SQL:

    Figure 2.1 – The compiler reports a type safety error

    Figure 2.1 – The compiler reports a type safety error

    Important Note

    Lukas Eder said this: As you probably know, the IDEs help writing SQL and JPQL strings, which is nice. But IDEs doesn't fail the build when a column name changes. Well, having type-safe queries covers this aspect, and the IDE can fail the build. So, thanks to jOOQ's fluency and expressiveness, the IDE can provide code completion and refactoring support. Moreover, with jOOQ, the bind variables are part of a non-dynamic Abstract Syntax Tree (AST); therefore, it is not possible to expose SQL injection vulnerabilities this way.

    OK, but how do we obtain this Java-based schema?

    Generating a jOOQ Java-based schema

    All the previous queries were referencing the database schema explicitly by placing the table or column name between quotes and passing them as arguments to the jOOQ built-in table() and field() methods respectively.

    But, using the jOOQ Code Generator allows the SQL statements expressed via jOOQ's query DSL API to take advantage of a Java-based schema that mirrors the one from the database. The code generation part is the job of the jOOQ generation tool (its starting point is the org.jooq.codegen.GenerationTool class).

    Having a Java-based schema is quite useful. The SQL statements can be expressed via the Java data access layer and executed against the underlying database schema. Besides being type-safe, these SQL statements are not prone to typos, are easy to refactor (for example, to rename a column), and are less verbose than referencing the database schema explicitly.

    jOOQ comes with several solutions for generating the Java-based schema via the jOOQ Code Generator. Mainly, jOOQ can generate the Java-based schema by applying the technique of reverse engineering to the database directly, the DDL files, JPA entities, or XML files containing the schema. Next, we will tackle the first three approaches, starting with the first approach, which generates the Java-based schema directly from the database. Mainly, we will use Flyway to migrate the database (Liquibase is supported as well), which is subsequently reverse engineered by jOOQ to obtain the Java-based schema.

    Code generation from a database directly

    The following figure represents the jOOQ Java-based schema generation flow:

    Figure 2.2 – Java-based schema generation

    Figure 2.2 – Java-based schema generation

    So far, jOOQ will regenerate the Java-based schema every time the application starts (runs).

    In other words, even if the database schema has not changed, jOOQ will regenerate the Java-based schema at each run. Obviously, this is preferable to regenerating the Java-based schema only when the underlying database schema is missing or has changed (for instance, a new column has been added to a table); otherwise, this is just a waste of time.

    Conscious schema change management is a good thing, and having a tool for this is great! Most probably, you'll choose between Flyway and Liquibase. While we will only cover the Flyway approach in the next section, Liquibase is very well represented in the jOOQ manual (https://www.jooq.org/doc/latest/manual/code-generation/codegen-liquibase/).

    Adding Flyway with Maven

    Flyway is a great tool for database migration (https://flywaydb.org/). Mainly, Flyway keeps track of database schema modifications via a table named flyway_schema_history (or schema_version in Flyway prior to version 5). This table is automatically added to the database and is maintained by Flyway itself.

    Typically, in Spring Boot, Flyway reads and executes all the database migration scripts located in the indicated path (the default path is src/main/resources/db/migration). For instance, in this book, we use an explicit path that points to a location outside the applications in the root folder (${root}/db/migration). We do this because we want

    Enjoying the preview?
    Page 1 of 1