1. введение
Jinq обеспечивает интуитивно понятный и удобный подход для запросов к базам данных на Java. В этом уроке мы рассмотрим как настроить проект Spring для использования Jing и некоторые его функции, проиллюстрированные простыми примерами.
2. Зависимости Maven
Нам нужно будет добавить зависимость соединения в pom.xml файл:
org.jinq jinq-jpa 1.8.22
Для Spring мы добавим зависимость Spring ORM в pom.xml файл:
org.springframework spring-orm 5.3.3
Наконец, для тестирования мы будем использовать базу данных H2 в памяти, поэтому давайте также добавим эту зависимость вместе с spring-boot-starter-data-jpa в pom.xml файл:
com.h2database h2 1.4.200 org.springframework.boot spring-boot-starter-data-jpa 2.4.0
3. Понимание Jinq
Junk помогает нам писать более простые и читаемые запросы к базе данных, предоставляя свободный API, который внутренне основан на API потока Java.
Давайте рассмотрим пример, где мы фильтруем автомобили по модели:
jinqDataProvider.streamAll(entityManager, Car.class) .where(c -> c.getModel().equals(model)) .toList();
Jinq переводит приведенный выше фрагмент кода в SQL-запрос эффективным способом , поэтому конечным запросом в этом примере будет:
select c.* from car c where c.model=?
Поскольку мы не используем обычный текст для написания запросов и вместо этого используем типобезопасный API, этот подход менее подвержен ошибкам.
Кроме того, Jinq стремится обеспечить более быструю разработку, используя общие, легко читаемые выражения.
Тем не менее, он имеет некоторые ограничения в количестве типов и операций, которые мы можем использовать, как мы увидим далее.
3.1. Ограничения
Jinq поддерживает только основные типы в JPA и конкретный список функций SQL. Он работает путем перевода лямбда-операций в собственный SQL-запрос путем сопоставления всех объектов и методов в тип данных JPA и функцию SQL.
Поэтому мы не можем ожидать, что инструмент переведет каждый пользовательский тип или все методы типа.
3.2. Поддерживаемые Типы данных
Давайте рассмотрим поддерживаемые типы данных и поддерживаемые методы:
- String – equals() , compareTo() только методы
- Примитивные типы данных – арифметические операции
- Перечисления и пользовательские классы – поддерживает только
- java.util.Коллекция – содержит()
- Дата API – равно() , до() , после() только методы
Примечание: если бы мы хотели настроить преобразование из объекта Java в объект базы данных, нам нужно было бы зарегистрировать нашу конкретную реализацию Преобразователь атрибутов в Джинке.
4. Интеграция Jinq С Пружиной
Jinq нуждается в экземпляре EntityManager , чтобы получить контекст сохранения. В этом уроке мы представим простой подход с Spring, чтобы заставить Jinq работать с EntityManager , предоставляемым Hibernate .
4.1. Интерфейс репозитория
Spring использует концепцию репозиториев для управления сущностями. Давайте посмотрим на наш CarRepository интерфейс, где у нас есть метод получения Car для данной модели:
public interface CarRepository { OptionalfindByModel(String model); }
4.2. Репозиторий абстрактной базы
Далее, нам понадобится базовый репозиторий , чтобы предоставить все ненужные возможности:
public abstract class BaseJinqRepositoryImpl{ @Autowired private JinqJPAStreamProvider jinqDataProvider; @PersistenceContext private EntityManager entityManager; protected abstract Class entityType(); public JPAJinqStream stream() { return streamOf(entityType()); } protected JPAJinqStream streamOf(Class clazz) { return jinqDataProvider.streamAll(entityManager, clazz); } }
4.3. Реализация репозитория
Теперь все, что нам нужно для Джинка, – это EntityManager экземпляр и класс типа сущности.
Давайте посмотрим реализацию репозитория Car , используя наш базовый репозиторий Jinq, который мы только что определили:
@Repository public class CarRepositoryImpl extends BaseJinqRepositoryImplimplements CarRepository { @Override public Optional findByModel(String model) { return stream() .where(c -> c.getModel().equals(model)) .findFirst(); } @Override protected Class entityType() { return Car.class; } }
4.4. Подключение устройства JinqJPAStreamProvider
Чтобы подключить экземпляр JinqJPAStreamProvider , мы добавим конфигурацию поставщика Jinq:
@Configuration public class JinqProviderConfiguration { @Bean @Autowired JinqJPAStreamProvider jinqProvider(EntityManagerFactory emf) { return new JinqJPAStreamProvider(emf); } }
4.5. Настройка приложения Spring
Последним шагом является настройка нашего приложения Spring с помощью Hibernate и нашей конфигурации Jinq. В качестве ссылки см. наш файл application.properties , в котором мы используем экземпляр H2 в памяти в качестве базы данных:
spring.datasource.url=jdbc:h2:~/jinq spring.datasource.username=sa spring.datasource.password= spring.jpa.hibernate.ddl-auto=create-drop
5. Руководство по запросу
Jinq предоставляет множество интуитивно понятных опций для настройки конечного SQL-запроса с помощью select, where, |/joins и многого другого. Обратите внимание, что они имеют
5.1. Где
Предложение where позволяет применять несколько фильтров к сбору данных.
В следующем примере мы хотим отфильтровать автомобили по модели и описанию:
stream() .where(c -> c.getModel().equals(model) && c.getDescription().contains(desc)) .toList();
И это SQL, который переводит Jinq:
select c.model, c.description from car c where c.model=? and locate(?, c.description)>0
5.2. Выберите
В случае, если мы хотим получить только несколько столбцов/полей из базы данных, нам нужно использовать предложение select .
Чтобы сопоставить несколько значений, Jinq предоставляет несколько классов Tuple , содержащих до восьми значений:
stream() .select(c -> new Tuple3<>(c.getModel(), c.getYear(), c.getEngine())) .toList()
И переведенный SQL:
select c.model, c.year, c.engine from car c
5.3. Присоединяется
Jinq способен разрешать отношения “один к одному” и “много к одному” , если сущности правильно связаны.
Например, если мы добавим сущность производителя в Car :
@Entity(name = "CAR") public class Car { //... @OneToOne @JoinColumn(name = "name") public Manufacturer getManufacturer() { return manufacturer; } }
И Производитель юридическое лицо со списком Автомобилей ов:
@Entity(name = "MANUFACTURER") public class Manufacturer { // ... @OneToMany(mappedBy = "model") public ListgetCars() { return cars; } }
И Производитель юридическое лицо со списком
Optionalmanufacturer = stream() .where(c -> c.getModel().equals(model)) .select(c -> c.getManufacturer()) .findFirst();
Как и ожидалось, Jinq будет использовать внутреннее предложение SQL join в этом сценарии:
select m.name, m.city from car c inner join manufacturer m on c.name=m.name where c.model=?
На случай, если нам понадобится больше контроля над присоединиться предложения для реализации более сложных отношений над сущностями, таких как отношение “многие ко многим”, мы можем использовать присоединиться метод:
List> list = streamOf(Manufacturer.class) .join(m -> JinqStream.from(m.getCars())) .toList()
Наконец, мы могли бы использовать SQL-предложение left outer join, используя метод left Outer Join вместо метода join .
5.4. Агрегации
Все примеры, которые мы представили до сих пор, используют методы ToList или findFirst – для возврата конечного результата нашего запроса в Jinq.
Помимо этих методов, у нас также есть доступ к другим методам для агрегирования результатов .
Например, давайте используем метод count , чтобы получить общее количество автомобилей для конкретной модели в нашей базе данных:
long total = stream() .where(c -> c.getModel().equals(model)) .count()
И окончательный SQL использует метод count SQL, как и ожидалось:
select count(c.model) from car c where c.model=?
Jinq также предоставляет методы агрегирования, такие как sum , average , min , max, и возможность комбинировать различные агрегации .
5.5. Разбиение на страницы
В случае, если мы хотим читать данные пакетами, мы можем использовать методы limit и skip .
Давайте рассмотрим пример, где мы хотим пропустить первые 10 автомобилей и получить только 20 предметов:
stream() .skip(10) .limit(20) .toList()
И сгенерированный SQL:
select c.* from car c limit ? offset ?
6. Заключение
Вот и все. В этой статье мы рассмотрели подход к настройке
Мы также кратко рассмотрели преимущества Jinq и некоторые из его основных функций.
Как всегда, источники можно найти на GitHub .