Първи стъпки с jOOQ

1. Въведение

В този урок ще направим кратка обиколка на стартиране на приложение с jOOQ (Java Object Orientted Query). Тази библиотека генерира Java класове въз основа на таблиците на базата данни и ни позволява да създаваме безопасни за тип SQL заявки чрез нейния плавен API.

Ще разгледаме цялата настройка, връзката с база данни PostgreSQL и няколко примера за CRUD операции.

2. Зависимости на Maven

За библиотеката jOOQ ще са ни необходими следните три зависимости jOOQ:

 org.jooq jooq 3.13.4   org.jooq jooq-meta 3.13.4   org.jooq jooq-codegen 3.13.4 

Ще ни е необходима и една зависимост за драйвера на PostgreSQL:

 org.postgresql postgresql 42.2.16 

3. Структура на базата данни

Преди да започнем, нека създадем проста DB схема за нашите примери. Ще използваме проста връзка между автор и член :

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/baeldung"; 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 :

   org.postgresql.Driver jdbc:postgresql://db_url:5432/baeldung_database username password   org.jooq.codegen.JavaGenerator  org.jooq.meta.postgres.PostgresDatabase public .*    com.baeldung.jooq.model C:/projects/baeldung/tutorials/jooq-examples/src/main/java   

Персонализираната конфигурация изисква промени в раздел, където поставяме идентификационните данни на базата данни и в раздел, в който конфигурираме името на пакета и директорията за местоположение за класове, които ще генерираме.

За да изпълним инструмента за генериране на код jOOQ, трябва да изпълним следния код:

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

След като генерирането завърши, ще получим двата следните класа, всеки съответстващ на неговата таблица на базата данни:

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

6. CRUD операции

Сега нека да разгледаме няколко основни CRUD операции, които можем да изпълним с библиотеката jOOQ.

6.1. Създаване

Първо, нека създадем нов запис на статия . За целта трябва да извикаме метода newRecord с подходяща препратка към таблицата като параметър:

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. Четене

Сега да видим как можем да четем стойности от базата данни. Като пример, нека изберете всички автори:

Result 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
    
      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. Актуализиране

To update a given record, we can use the update method from the DSLContext object combined with a set method invocations for every field we need to change. This statements should be followed by a where clause with a proper match condition:

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

The update query will run only after we call the execute method. As a return value, we'll get an integer equal to the number of records that were updated.

It's also possible to update an already fetched record by executing its store method:

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

The store method will return 1 if the operation was successful or 0 if the update was not necessary. For example, nothing was matched by the condition.

6.4. Deleting

To delete a given record, we can use the delete method from the DSLContext object. The delete condition should be passed as a parameter in the following where clause:

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

The delete query will run only after we call the execute method. As a return value, we'll get an integer equal to the number of deleted records.

It's also possible to delete an already fetched record by executing its delete method:

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

Методът за изтриване ще върне 1, ако операцията е била успешна, или 0, ако изтриването не е било необходимо. Например, когато нищо не съответства на условието.

7. Заключение

В тази статия научихме как да конфигурираме и създадем просто CRUD приложение, използвайки рамката jOOQ. Както обикновено, целият изходен код е достъпен в GitHub.