В предишен пост видяхме кога е добра идея да използваме ORM и кога да пишем сами SQL-a е за предпочитане.

Да предположим, че за определен случай сме решили да използваме чист SQL. Примерно имаме нужда от много комплексни заявки към нашата база данни. В Java света това в повечето случаи означава JDBC.

За съжаление JDBC не е без проблеми:

  • „шумно“ API, много церемонии за да направиш и най-малкото нещо
  • SQL манипулация -> манипулация на текст
  • Превръщането на в обекти и обратно е проблем (защото не е ORM :))

Проекти като Spring JdbcTemplate ни помагат с проблемите на „шумното“ API, както и донякъде превръщането в обекти.

Какво обаче да направим с SQL-a?

  • грешките се откриват след като изпълним заявката
  • липсва концепция за променливи/функции както при Java кода – при по-сложни заявки става много трудно да разберем какво се случва

Обикновено ни се налага да използваме SQL директно когато имаме по-сериозни заявки, често простиращи се в много редове. Търсенето на това къде сме пропуснали затваряща скоба или просто да разберем логически какво се случва в такъв случай е проблем, който няма лесно решение.

Преизползване на SQL заявките на практика означава манипулация на String.

Именно за да реши тези проблеми е създадена jOOQ.

Какво е jOOQ?

jOOQ е съкращение от Java Object Oriented Querying и е изградена около простата философия: „SQL First“.

Какво представлява и как се използва можем да видим от този прост пример:  

jOOQ дефинира fluent API, който ни позволява да използваме autocomplete на нашето IDE за да ни помага в писането.

Така вече не пишем SQL като String, а като Java код! До какво води това?
– Откриване на много от грешките по време на компилация
По-малко синтактични грешки
Лесно преизползване на части от заявката – в Java има променливи
Type-Safe SQL

Как можем да го използваме и откъде се взе тoва PERSONS?

Къде можем да открием jOOQ?

Ако се чудите откъде се взе jooq променливата в горния пример, ето как можем да я дефинираме:

Директно
Maven Repository.

Където connection е java.sql.Connection, а dialect – диалекта на вашия SQL. Примерно org.jooq.SQLDialect.POSTGRES

Със Spring
Maven Repository

Предполага се, че вече има DataSource дефиниран:

Диалекта, който изпозлваме указваме в application.properties:


Лиценз?

Отговорът на този въпрос се крие в отговора на въпроса – платена ли е базата ни? За безплатните бази от данни, jOOQ също е безплатен. За платените се налага да си вземем лиценз.

Code generation

Помните ли тези два реда код?

Откъде се взе това PERSONS?

По време на всеки build, jOOQ сe свързва със схемата на нашата база, извлича оттам информацията за всички обекти в нея – tables, views, sequences и т.н. По подразбиране тези генерирани обекти отиват директно в build директорията ни, а package името е org.jooq.generated. Това се случва със специален plugin към build-a. Конфигурирането на такъв е лесно. Пример с Gradle можете да видите в проекта, който ще намерите в края на този пост.

Това, което е важно в момента е, че jOOQ генерира за вас Java обекти, които да използвате в заявките си и отговарят на таблиците и другите обекти във вашата база.

Ето и как изглежда генерирания код в IDE:

Подаване на параметри

Това е примерна заявка, която подава параметър:

Забележете ParamType.INLINED подаден като параметър на getSQL(). Без него в създадения SQL, параметъра „Doe“ няма да фигурира, а ще получите SQL, „подготвен“ за PreparedStatement.

Това дали искате да използвате INLINED или не зависи от вашия use case.

SQL reuse

Преизползването на SQL код е вече тривиална задача, просто използваме Java променливи. Така бихме могли да отделим някой WHERE, subquery, а защо не и да използваме UNION?

Нека имаме тези две заявки:

Ако искаме да ги обединим с UNION и да вземем получения SQL, нужно е просто да напишем това:

Друг пример би бил да подаваме различни стойности на WHERE:

Възможностите са много 🙂

Database schema refactoring

Вече научихме, че jOOQ при всеки build генерира за вас код, отговарящ на схемата на вашата база. И тук идва едно голямo предимство – ако променим базата, променяме и генерирания код.

Ако промяната не е съвместима – примерно изтрили сме колона, която използваме някъде, компилаторът моментално ще ви каже къде има проблем.

Това позволява бързи и лесни промени по заявките ви, без опасност да пропуснете нещо.

SQL Execution

Type-safe SQL е безспорно страхотна функционалност, но не решава всички наши проблеми. jOOQ може и да изпълнява SQL:

В случай, че заявката не е SELECT, ами UPDATE/DELETE, използваме  execute().

В повечето случаи обаче използваме jOOQ за четене, тогава използваме fetch():

Ще разгледаме малко по-подробно какво правят fetch(), fetchOne() и подобните им функции в jOOQ.

Fetching Data

Първото интересно нещо във fetch() e, че връща List от обекти:

Оттам можем да оперираме с него като обикновен List.

Ако е нужен само един резултат, използваме fetchOne():

Интересни също са вариантите fetchInto(…):

Като jOOQ може директно да вкарва резултатите в направен от нас обект или дори JPA Bean, стига да е дефиниран правилно:

Ако искаме можем да подадем на fetch() наш Object mapper, който да превърне върнатия record в обект.

Вариантите на fetch() в jOOQ са много, включително такива като fetchIntoOptional(), fetchResultSet(), fetchLazy() и много други. Можете дори да използвате само тази функционалност на jOOQ като конвертирате съществуващ ResultSet в обекти:

CRUD Operations

Често ни се налага да вкараме данни в базата, което е твърде много работа ако използваме само JDBC. В идеалния случай използваме JPA/Hibernate, които решават този проблем. jOOQ също предоставя такава функционалност. Макар и не толкова комплексна колкото JPA, тя върши чудесна работа ако няма да ви се налага да вкарвате сложни структури от данни в базата. Друго предимство е колко е лесно да започнете, благодарение на вече генерирания от вашата база код.

Ако погледнем още веднъж какво има в генерирания от jOOQ код, може да ни направи впечатление, че има много обекти, отговарящи на таблици в нашата база и завършващи на Record.

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

След извикване на update(), обектът ще бъде променен в базата. Освен да променяме, можем естествено и да  създаваме нови, както и да трием:

Забележете, че id, което не зададохме, вече съществува за този обект – т.е върнали сме го от базата след като е бил създаден.

Ако имате сравнително прости операции за писане в базата и/или изобщо не искате да се занимавате с JPA (което обикновено не е препоръчително!), вижте тази функционалност на jOOQ.

Как да използваме jOOQ в нашия проект?

Както написахме в предишния пост, не е нужно да избирате един инструмент. Изберете най-добрия за вашия случай.

Използвате JPA? – ако на места ви се налага да използвате SQL, добавете jOOQ. Ако искате повече детайли как може да стане това – вижте тази статия.

Използвате JDBC? – пълна миграция към jOOQ е възможна. Стъпка по стъпка бихте могли да замените вашите query generation (type-safe SQL), query execution и data fetching решенията си с jOOQ.

Заключение

Много от примерния код, видим в този пост се намира в това Github репо.

Простата философия на jOOQ e „SQL First“.

Ако ви се налага да пишете SQL, но не сте доволни от възможностите които JDBC или вашия framework ви дават, вижте какво jOOQ може да ви предложи! Тя е лека, разработва се от години (10 години към момента!). Поддържа се активно и има добро community. Добре документирана e и писана с идея да бъде лесна за използване.

За повече информация посетете jooq.org, много добър ресурс и е книгата на Vlad MihalceaHigh Performance Java Persistence, в която има секция, посветена на jOOQ.

Имате въпроси? Забелязахте неточност? Моля, споделете в коментарите!


Автор:

Костадин Голев

>>> Костадин Голев е Team Lead в Ocado Technology.
>>> Той е Java програмист и team lead с повече от 10 години опит.
>>> Има силен интерес към test automation.
>>> Coderetreat & coding dojo организатор.
>>> Обича да пише в kgolev.com.

 

 

 


Стани част от Java потребителската група на DEV.BG.

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

You have Successfully Subscribed!

Прочети още:
Кога и как да интегрираме автоматизация с Postman
Обучение с Утвърждение (Част 1)

Share This