[Перевод] Как упростить доступ к данным с MySQL и Jakarta Data

b490a4a69d2859b1beeb8e2bc94a4c78.png

Многие приложения, особенно в сегменте enterprise, сохраняют или получают доступ к данным в какой-либо форме. Реляционные базы данных по-прежнему остаются самым популярным механизмом для управления данными, несмотря на конкуренцию со стороны таких технологий, как NoSQL базы данных. В этой статье рассмотрим некоторые концепции доступа к данным и то, как новая спецификация Jakarta Data упрощает эту задачу для разработчиков приложений.

Сохранение данных

Я начну обсуждение с обзора основных концепций сохранения данных. Если вы с ними уже знакомы, можете пропустить этот раздел и перейти к следующему, где представлены примеры кода.

CRUD
Чаще всего в приложениях для работы с данными используются следующие операции — создание, чтение, обновление и удаление (CRUD: create, read, update, delete). CRUD-операции обычно применяются с реляционными базами данных, но их можно также применять к любым механизмам управления данными. Написание кода для этих операций, как правило, представляет собой повторяющуюся задачу, которая в основном состоит из шаблонного кода.

ORM
Объектно-реляционное отображение, или преобразование (ORM, Object-relational mapping), как следует из названия, занимается преобразованием объектов в объектно-ориентированном языке программирования в данные реляционной базы данных. Есть множество ORM-фреймворков, которые помогают разработчикам выполнять эту задачу. Jakarta Persistence, ранее известная как JPA, представляет собой спецификацию, которая стандартизирует управление сохранением данных и объектно-реляционное отображение для Java-приложений.

Шаблон Repository
Существует множество шаблонов и стратегий, таких как Data Access Object («объект доступа к данным») (DAO), Repository («репозиторий»), Active Record («активная запись») и другие, которые часто используются для структурирования кода, связанного с CRUD-операциями. В этой статье я использую шаблон Repository.

Цель шаблона Repository (описанного в книге Мартина Фаулера Patterns of Enterprise Application Architecture) — исключить детали, связанные с сохранением данных, из доменной модели приложения. Репозитории представляют собой классы, инкапсулирующие логику доступа к данным, что позволяет разделить механизмы сохранения и доменную модель.

Шаблон Repository стал популярным и широко используется благодаря таким технологиям, как Spring Data. Именно Spring Data вдохновил разработчиков Jakarta Data.

Jakarta Data
Jakarta Data — это новая спецификация, предложенная для включения в Jakarta EE 11 (прим. пер: релиз Jakarta Data 1.0 состоялся 30 сентября 2024 года). Реализуя шаблон Repository, Jakarta Data упрощает доступ к данным и сокращает объём шаблонного кода. Разработчику нужно лишь определить интерфейс, представляющий репозиторий, и сущность, представляющую таблицу базы данных. Реализация Jakarta Data предоставит готовую реализацию репозитория.

Пример с MySQL

Этот простой пример демонстрирует, как Jakarta Data упрощает работу с сохранением данных, устраняя необходимость в шаблонном коде. В этом примере используются следующие технологии:

Также потребуется установить Apache Maven и JDK. Этот код проверен на Java 20, но может работать и с другими версиями.

В качестве среды выполнения в примере используется Open Liberty. Однако, если у вас есть другая реализация, вы сможете заменить Open Liberty без изменения кода.

Шаг 1. Убедитесь, что Apache Maven и JDK установлены.
Вы должны увидеть что-то вроде:

$ mvn --version
Apache Maven 3.8.2 (ea98e05a04480131370aa0c110b8c54cf726c06f)
Maven home: /home/ivar/.sdkman/candidates/maven/current
Java version: 20.0.1, vendor: Eclipse Adoptium, runtime: /home/ivar/.sdkman/candidates/java/20.0.1-tem
Default locale: en_US, platform encoding: UTF-8

Шаг 2. Установите и настройте MySQL.
Скачайте MySQL с сайта или используйте любимый менеджер пакетов. Вот пример команды для Ubuntu:

$ sudo apt-get install mysql-server

Шаг 3. Войдите в MySQL Shell

sudo mysql -u root

Шаг 4. Создайте базу данных и пользователя

mysql> create database dukes_data;
mysql> use dukes_data;
mysql> create user 'duke'@'localhost' identified by 'duke';
mysql> grant all privileges on dukes_data to 'duke'@'localhost';

Шаг 5. Загрузите код из моего репозитория на GitHub, а затем скомпилируйте и запустите его с помощью Maven.

Для этого выполните следующую команду:

$ mvn liberty:run

Теперь приложение готово для использования.

Шаг 6. Доступны три конечных точки (эндпоинта):

  1. Получить список всех приветствий (GET)

  2. Найти приветствие по имени отправителя (GET)

  3. Добавить новое приветствие (POST)

Вот как это работает.

Чтобы получить список всех приветствий, используйте следующий запрос:

http://localhost:9080/dukes-data/api/greetings/ 

Ожидаемый ответ, так как данных пока нет:

[]

Чтобы найти приветствие от Дьюка, используйте следующий запрос:

http://localhost:9080/dukes-data/api/greetings/duke 

Поскольку данных пока нет, вы получите следующий ответ:

duke not found

Чтобы добавить приветствие от Дьюка, выполните запрос POST с необходимыми данными.

$ echo -n '{"message":"Hello from Duke", "name":"Duke"}' | http post :9080/dukes-data/api/greetings

Чтобы снова получить список всех приветствий, используйте:

http://localhost:9080/dukes-data/api/greetings/

Теперь вы должны увидеть ожидаемый ответ, который включает добавленное приветствие.

[
  {
    id: 1,
    message: "Hello from Duke",
    name: "Duke"
  }
]

Наконец, чтобы снова найти приветствие от Дьюка, используйте следующий запрос:

http://localhost:9080/dukes-data/api/greetings/duke

Ожидаемый ответ:

Hello from Duke

Пример кода

Приложение состоит из четырёх классов: GreetingApplication, GreetingResource, Greeting и GreetingRepository.

  1. GreetingApplication
    Этот класс настраивает приложение Jakarta REST. В данном случае требуется только указание пути приложения.

package dukes.data;

import jakarta.ws.rs.ApplicationPath;
import jakarta.ws.rs.core.Application;

@ApplicationPath("/api")
public class GreetingApplication extends Application {
}
  1. GreetingResource
    Этот класс предоставляет три API-метода: для получения всех приветствий, получения одного приветствия и добавления нового приветствия.

package dukes.data;

import jakarta.inject.Inject;
import jakarta.validation.Valid;
import jakarta.ws.rs.*;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response;

import java.util.List;

@Path("/greetings")
public class GreetingResource {

    @Inject
    private GreetingRepository greetingRepository;

    @GET
    @Path("/{name}")
    @Produces(MediaType.TEXT_PLAIN)
    public String findOne(@PathParam("name") String name) {

       return greetingRepository.findByNameIgnoreCase(name)
               .map(Greeting::getMessage)
               .orElse(name + " not found");
    }

    @GET
    @Produces(MediaType.APPLICATION_JSON)
    public List findAll() {

        return greetingRepository.findAll()
                .toList();
    }

    @POST()
    @Consumes(MediaType.APPLICATION_JSON)
    public Response addGreeting(Greeting greeting) {

        Greeting saved = greetingRepository.save(greeting);
        return Response.ok("Created greeting: " + greeting.getId()).build();
    }
}
  1. Greeting
    Класс Greeting определяет сущность, которая сохраняется в базе данных — это сущность Jakarta Persistence с тремя полями.

    • Аннотация @Entity определяет её как сущность Jakarta Persistence.

    • Аннотации @Id и @GeneratedValue указывают первичный ключ и способ его генерации.
      Помимо этого, это обычный Java-класс (POJO).

package dukes.data;

import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;

@Entity
public class Greeting {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;
    private String name;
    private String message;

    // constructor/getters/setters
}
  1. GreetingRepository
    Здесь начинается самое интересное. Это простой интерфейс, который расширяет CrudRepository и аннотирован @Repository. Этого достаточно, чтобы реализация Jakarta Data сгенерировала методы для всех CRUD-операций, а также несколько удобных методов, таких как count, existsById и различные методы поиска.

package dukes.data;

import jakarta.data.repository.CrudRepository;
import jakarta.data.repository.Repository;

import java.util.Optional;

@Repository
public interface GreetingRepository extends CrudRepository {

    Optional findByNameIgnoreCase(String name);
}

Единственный метод, определённый разработчиком, — это findByNameIgnoreCase. Как следует из названия, этот метод ищет в базе данных строки с указанным именем. Jakarta Data сгенерирует метод, который выполняет именно это.

Заключение

Jakarta Data — это очень интересное дополнение к Jakarta EE. Оно повышает продуктивность разработчиков и качество кода, избавляет от необходимости писать подверженный ошибкам шаблонный код. Jakarta Data теперь доступна во всех продуктах, совместимых с платформой Jakarta EE 11.

Jakarta Data и Jakarta Persistence полностью абстрагированы от используемого механизма сохранения данных, поэтому можно использовать любую реляционную базу данных. В этом примере была использована MySQL. Она остаётся одной из самых популярных баз данных благодаря ряду причин:

  • бесплатная и открытая лицензия,

  • доступность на множестве платформ,

  • простота установки и начала работы,

  • наличие обширной документации и ресурсов в интернете.

При необходимости доступны также коммерческие варианты MySQL.

Как видно, Jakarta Data предлагает богатый язык и аннотации для создания методов запросов с широким выбором параметров сортировки. Обязательно ознакомьтесь с этой спецификацией и делитесь своими отзывами с проектом, который занимается её разработкой.

В заключение всех начинающих Java-разработчиков приглашаем на открытые уроки, которые пройдут в январе:

  • 16 января: «Реализация простого HTTP-сервера на Java Core». Урок поможет вам лучше понять принципы работы application server’ов и контейнеров сервлетов. Записаться

  • 28 января: «Алгоритмическая сложность коллекций». Разберём принципы, которые играют ключевую роль для повышения производительности кода. Записаться

Habrahabr.ru прочитано 825 раз