1. Введение
В этом руководстве мы кратко рассмотрим запуск приложения с помощью jOOQ (объектно-ориентированный запрос Java). Эта библиотека генерирует классы Java на основе таблиц базы данных и позволяет нам создавать безопасные для типов SQL-запросы через свободный API.
Мы рассмотрим всю настройку, подключение к базе данных PostgreSQL и несколько примеров операций CRUD.
2. Зависимости Maven
Для библиотеки jOOQ нам понадобятся следующие три зависимости jOOQ :
<dependency>
<groupId>org.jooq</groupId>
<artifactId>jooq</artifactId>
<version>3.13.4</version>
</dependency>
<dependency>
<groupId>org.jooq</groupId>
<artifactId>jooq-meta</artifactId>
<version>3.13.4</version>
</dependency>
<dependency>
<groupId>org.jooq</groupId>
<artifactId>jooq-codegen</artifactId>
<version>3.13.4</version>
</dependency>
Нам также понадобится одна зависимость для драйвера PostgreSQL :
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>42.2.16</version>
</dependency>
3. Структура базы данных
Прежде чем мы начнем, давайте создадим простую схему БД для наших примеров. Мы будем использовать простые отношения Author
и Article
:
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-адрес базы данных. Мы будем использовать эти свойства для создания объекта Connection
с помощью DriverManager
и его метода getConnection
:
String userName = "user";
String password = "pass";
String url = "jdbc:postgresql://db_host:5432/foreach";
Connection conn = DriverManager.getConnection(url, userName, password);
Далее нам нужно создать экземпляр DSLContext
. Этот объект будет нашей точкой входа для интерфейсов jOOQ:
DSLContext context = DSL.using(conn, SQLDialect.POSTGRES);
В нашем случае мы передаем диалект POSTGRES
, но доступно несколько других, таких как 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/foreach_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.foreach.jooq.model</packageName>
<directory>C:/projects/foreach/tutorials/jooq-examples/src/main/java</directory>
</target>
</generator>
</configuration>
Пользовательская конфигурация требует изменений в разделе <jdbc>
, где мы размещаем учетные данные базы данных, и в разделе <target>
, в котором мы настраиваем имя пакета и каталог местоположения для классов, которые мы будем генерировать.
Чтобы запустить инструмент генерации кода jOOQ, нам нужно запустить следующий код:
GenerationTool.generate(
Files.readString(
Path.of("jooq-config.xml")
)
);
После завершения генерации мы получим два следующих класса, каждый из которых соответствует своей таблице базы данных:
com.foreach.model.generated.tables.Article;
com.foreach.model.generated.tables.Author;
6. CRUD
-операции
Теперь давайте рассмотрим несколько основных операций CRUD, которые мы можем выполнять с библиотекой jOOQ.
6.1. Создание
Во-первых, давайте создадим новую запись статьи .
Для этого нам нужно вызвать метод newRecord
с правильной ссылкой на таблицу в качестве параметра:
ArticleRecord article = context.newRecord(Article.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. Чтение
Теперь давайте посмотрим, как мы можем читать значения из базы данных. В качестве примера выберем всех авторов:
Result<Record> authors = context.select()
.from(Author.AUTHOR)
.fetch();
Здесь мы используем метод select
в сочетании с предложением from
, чтобы указать, из какой таблицы мы хотим читать. Вызов метода выборки
выполняет запрос SQL и возвращает сгенерированный результат.
Объект Result
реализует интерфейс Iterable
, поэтому легко перебирать каждый элемент. И имея доступ к одной записи, мы можем получить ее параметры с помощью метода getValue
с правильной ссылкой на поле:
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(Author.AUTHOR)
.fetch();
Мы также можем выбрать один объект с помощью метода fetchOne
. Параметрами для этого являются ссылка на таблицу и условие соответствия соответствующей записи.
В нашем случае давайте просто выберем автора
с идентификатором, равным 1:
AuthorRecord author = context.fetchOne(Author.AUTHOR, Author.AUTHOR.ID.eq(1))
Если ни одна запись не соответствует условию, метод fetchOne
вернет значение null
.
6.3. Обновление
Чтобы обновить данную запись, мы можем использовать метод обновления
из объекта DSLContext
в сочетании с вызовами метода set
для каждого поля, которое нам нужно изменить. За этими операторами должно следовать предложение where
с надлежащим условием соответствия:
context.update(Author.AUTHOR)
.set(Author.AUTHOR.FIRST_NAME, "David")
.set(Author.AUTHOR.LAST_NAME, "Brown")
.where(Author.AUTHOR.ID.eq(1))
.execute();
Запрос на обновление будет запущен только после того, как мы вызовем метод execute
. В качестве возвращаемого значения мы получим целое число, равное количеству обновленных записей.
Также возможно обновить уже извлеченную запись, выполнив ее метод хранения :
ArticleRecord article = context.fetchOne(Article.ARTICLE, Article.ARTICLE.ID.eq(1));
article.setTitle("A New Article Title");
article.store();
Метод store
вернет 1
, если операция прошла успешно, или 0
, если обновление не требуется. Например, ничего не соответствовало условию.
6.4. Удаление
Чтобы удалить данную запись, мы можем использовать метод удаления
из объекта DSLContext
. Условие удаления должно быть передано в качестве параметра в следующем предложении where
:
context.delete(Article.ARTICLE)
.where(Article.ARTICLE.ID.eq(1))
.execute();
Запрос на удаление будет запущен только после того, как мы вызовем метод execute
. В качестве возвращаемого значения мы получим целое число, равное количеству удаленных записей.
Также возможно удалить уже извлеченную запись, выполнив ее метод удаления :
ArticleRecord articleRecord = context.fetchOne(Article.ARTICLE, Article.ARTICLE.ID.eq(1));
articleRecord.delete();
Метод удаления
вернет 1
, если операция прошла успешно, или 0
, если удаление не требуется. Например, когда ничего не соответствовало условию.
7. Заключение
В этой статье мы узнали, как настроить и создать простое приложение CRUD с использованием платформы jOOQ. Как обычно, весь исходный код доступен на GitHub.