1. 简介

在本篇文章中,我们将快速了解如何使用 jOOQ(Java Object Oriented Query)来构建应用程序。jOOQ 是一个强大的数据库访问库,它通过代码生成的方式将数据库表映射为 Java 类,并提供一套流畅的 API 来编写类型安全的 SQL 查询。

我们将涵盖以下内容:

  • jOOQ 的基本配置
  • PostgreSQL 数据库连接
  • 一些常见的 CRUD 操作示例

2. Maven 依赖

要使用 jOOQ,我们需要添加如下三个核心依赖:

<dependency>
    <groupId>org.jooq</groupId>
    <artifactId>jooq</artifactId>
    <version>3.19.0</version>
</dependency>
<dependency>
    <groupId>org.jooq</groupId>
    <artifactId>jooq-meta</artifactId>
    <version>3.19.0</version>
</dependency>
<dependency>
    <groupId>org.jooq</groupId>
    <artifactId>jooq-codegen</artifactId>
    <version>3.19.0</version>
</dependency>

此外,我们还需要添加 PostgreSQL 驱动依赖:

<dependency>
    <groupId>org.postgresql</groupId>
    <artifactId>postgresql</artifactId>
    <version>42.5.4</version>
    <scope>runtime</scope>
</dependency>

3. 数据库结构

在开始之前,我们先定义一个简单的数据库结构,包含 AuthorArticle 两个表,它们之间是一对多的关系:

create table AUTHOR
(
    ID         integer PRIMARY KEY,
    FIRST_NAME varchar(255),
    LAST_NAME  varchar(255),
    AGE        integer
);

create table ARTICLE
(
    ID          integer PRIMARY KEY,
    TITLE       varchar(255) not null,
    DESCRIPTION varchar(255),
    AUTHOR_ID   integer
        CONSTRAINT fk_author_id REFERENCES AUTHOR
);

4. 数据库连接

接下来,我们看看如何连接数据库。首先,我们需要提供用户名、密码和完整的数据库 URL,然后使用 DriverManager.getConnection 方法创建一个 Connection 对象:

String userName = "user";
String password = "pass";
String url = "jdbc:postgresql://db_host:5432/baeldung";
Connection conn = DriverManager.getConnection(url, userName, password);

然后,我们需要创建一个 DSLContext 实例,这是 jOOQ 的入口类:

DSLContext context = DSL.using(conn, SQLDialect.POSTGRES);

这里我们使用的是 PostgreSQL 方言,jOOQ 还支持 H2、MySQL、SQLite 等多种数据库。

5. 代码生成

为了将数据库表映射为 Java 类,我们需要配置一个 jooq-config.xml 文件:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<configuration xmlns="http://www.jooq.org/xsd/jooq-codegen-3.13.0.xsd">
    
    <jdbc>
        <driver>org.postgresql.Driver</driver>
        <url>jdbc:postgresql://db_url:5432/baeldung_database</url>
        <user>username</user>
        <password>password</password>
    </jdbc>

    <generator>
        <name>org.jooq.codegen.JavaGenerator</name>

        <database>
            <name>org.jooq.meta.postgres.PostgresDatabase</name>
            <inputSchema>public</inputSchema>
            <includes>.*</includes>
            <excludes></excludes>
        </database>

        <target>
            <packageName>com.baeldung.jooq.model</packageName>
            <directory>C:/projects/baeldung/tutorials/jooq-examples/src/main/java</directory>
        </target>
    </generator>
</configuration>

在这个配置中,我们指定了数据库连接信息以及生成类的包名和目录。

然后,通过如下代码执行代码生成:

GenerationTool.generate(
  Files.readString(
    Path.of("jooq-config.xml")
  )    
);

生成完成后,我们会得到两个类,分别对应数据库中的表:

com.baeldung.model.generated.tables.Article;
com.baeldung.model.generated.tables.Author;

6. CRUD 操作

现在我们来看一些基本的 CRUD 操作。

6.1. 创建(Create)

首先,创建一个新的 Article 记录:

ArticleRecord article = context.newRecord(Article.ARTICLE);

这里的 Article.ARTICLE 是 jOOQ 自动生成的表引用。

然后设置字段值:

article.setId(2);
article.setTitle("jOOQ examples");
article.setDescription("A few examples of jOOQ CRUD operations");
article.setAuthorId(1);

最后调用 store() 方法保存到数据库:

article.store();

6.2. 查询(Read)

查询所有作者:

Result<Record> authors = context.select()
  .from(Author.AUTHOR)
  .fetch();

遍历并读取字段:

authors.forEach(author -> {
    Integer id = author.getValue(Author.AUTHOR.ID);
    String firstName = author.getValue(Author.AUTHOR.FIRST_NAME);
    String lastName = author.getValue(Author.AUTHOR.LAST_NAME);
    Integer age = author.getValue(Author.AUTHOR.AGE);

    System.out.printf("Author %s %s has id: %d and age: %d%n", firstName, lastName, id, age);
});

只查询部分字段:

Result<Record2<Integer, String>> articles = context.select(Article.ARTICLE.ID, Article.ARTICLE.TITLE)
  .from(Article.ARTICLE)
  .fetch();

查询单个记录:

AuthorRecord author = context.fetchOne(Author.AUTHOR, Author.AUTHOR.ID.eq(1));

如果未找到匹配记录,fetchOne 返回 null

6.3. 更新(Update)

更新记录:

context.update(Author.AUTHOR)
  .set(Author.AUTHOR.FIRST_NAME, "David")
  .set(Author.AUTHOR.LAST_NAME, "Brown")
  .where(Author.AUTHOR.ID.eq(1))
  .execute();

或者更新已获取的记录:

ArticleRecord article = context.fetchOne(Article.ARTICLE, Article.ARTICLE.ID.eq(1));
article.setTitle("A New Article Title");
article.store();

6.4. 删除(Delete)

删除记录:

context.delete(Article.ARTICLE)
  .where(Article.ARTICLE.ID.eq(1))
  .execute();

或者删除已获取的记录:

ArticleRecord articleRecord = context.fetchOne(Article.ARTICLE, Article.ARTICLE.ID.eq(1));
articleRecord.delete();

7. 总结

在这篇文章中,我们介绍了如何配置并使用 jOOQ 来构建一个简单的 CRUD 应用程序。jOOQ 通过类型安全的 API 和代码生成机制,使得数据库操作更加直观和可靠,非常适合需要复杂 SQL 查询的场景。✅

如果你追求更优雅的数据库访问方式,jOOQ 绝对值得一试。⚠️不过注意,它更适合那些对 SQL 有一定掌控力的开发者,而不是完全依赖 ORM 的团队。


原始标题:Getting Started with jOOQ | Baeldung