repository spring что это

Spring Data JPA

В статье опишу использование Spring Data.

Spring Data — дополнительный удобный механизм для взаимодействия с сущностями базы данных, организации их в репозитории, извлечение данных, изменение, в каких то случаях для этого будет достаточно объявить интерфейс и метод в нем, без имплементации.

1. Spring Repository

Основное понятие в Spring Data — это репозиторий. Это несколько интерфейсов которые используют JPA Entity для взаимодействия с ней. Так например интерфейс
public interface CrudRepository extends Repository
обеспечивает основные операции по поиску, сохранения, удалению данных (CRUD операции)

Есть и другие абстракции, например PagingAndSortingRepository.

Т.е. если того перечня что предоставляет интерфейс достаточно для взаимодействия с сущностью, то можно прямо расширить базовый интерфейс для своей сущности, дополнить его своими методами запросов и выполнять операции. Сейчас я покажу коротко те шаги что нужны для самого простого случая (не отвлекаясь пока на конфигурации, ORM, базу данных).

1. Создаем сущность

2. Наследоваться от одного из интерфейсов Spring Data, например от CrudRepository

3. Использовать в клиенте (сервисе) новый интерфейс для операций с данными

Здесь я воспользовался готовым методом findById. Т.е. вот так легко и быстро, без имплементации, получим готовый перечень операций из CrudRepository:

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

2. Методы запросов из имени метода

Запросы к сущности можно строить прямо из имени метода. Для этого используется механизм префиксов find…By, read…By, query…By, count…By, и get…By, далее от префикса метода начинает разбор остальной части. Вводное предложение может содержать дополнительные выражения, например, Distinct. Далее первый By действует как разделитель, чтобы указать начало фактических критериев. Можно определить условия для свойств сущностей и объединить их с помощью And и Or. Примеры

В документации определен весь перечень, и правила написания метода. В качестве результата могут быть сущность T, Optional, List, Stream. В среде разработки, например в Idea, есть подсказка для написания методов запросов.

repository spring что это. Смотреть фото repository spring что это. Смотреть картинку repository spring что это. Картинка про repository spring что это. Фото repository spring что это
Достаточно только определить подобным образом метод, без имплементации и Spring подготовит запрос к сущности.

3. Конфигурация и настройка

Весь проект доступен на github
github DemoSpringData

Здесь лишь коснусь некоторых особенностей.

В context.xml определенны бины transactionManager, dataSource и entityManagerFactory. Важно указать в нем также

путь где определены репозитории.

EntityManagerFactory настроен на работу с Hibernate ORM, а он в свою очередь с БД Oracle XE, тут возможны и другие варианты, в context.xml все это видно. В pom файле есть все зависимости.

4. Специальная обработка параметров

В методах запросов, в их параметрах можно использовать специальные параметры Pageable, Sort, а также ограничения Top и First.

5. Пользовательские реализации для репозитория

Предположим что в репозиторие нужен метод, который не получается описать именем метода, тогда можно реализовать с помощью своего интерфейса и класса его имплементирующего. В примере ниже добавлю в репозиторий метод получения сотрудников с максимальной оплатой труда.

Имплементирую интерфейс. С помощью HQL (SQL) получаю сотрудников с максимальной оплатой, возможны и другие реализации.

А также расширяю Crud Repository Employees еще и CustomizedEmployees.

Здесь есть одна важная особенность. Класс имплементирующий интерфейс, должен заканчиваться (postfix) на Impl, или в конфигурации надо поставить свой postfix

Проверяем работу этого метода через репозиторий

Другой случай, когда надо изменить поведение уже существующего метода в интерфейсе Spring, например delete в CrudRepository, мне надо что бы вместо удаления из БД, выставлялся признак удаления. Техника точно такая же. Ниже пример:

Теперь если в employeesCrudRepository вызвать delete, то объект будет только помечен как удаленный.

6. Пользовательский Базовый Репозиторий

В предыдущем примере я показал как переопределить delete в Crud репозитории сущности, но если это надо делать для всех сущностей проекта, делать для каждой свой интерфейс как то не очень. тогда в Spring data можно настроить свой базовый репозиторий. Для этого:
Объявляется интерфейс и в нем метод для переопределения (или общий для всех сущностей проекта). Тут я еще для всех своих сущностей ввел свой интерфейс BaseEntity (это не обязательно), для удобства вызова общих методов, его методы совпадают с методами сущности.

В конфигурации надо указать этот базовый репозиторий, он будет общий для всех репозиториев проекта

Теперь Employees Repository (и др.) надо расширять от BaseRepository и уже его использовать в клиенте.

Проверяю работу EmployeesBaseRepository

Теперь также как и ранее, объект будет помечен как удаленный, и это будет выполняться для всех сущностей, которые расширяют интерфейс BaseRepository. В примере был применен метод поиска — Query by Example (QBE), я не буду здесь его описывать, из примера видно что он делает, просто и удобно.

7. Методы запросов — Query

Ранее я писал, что если нужен специфичный метод или его реализация, которую нельзя описать через имя метода, то это можно сделать через некоторый Customized интерфейс ( CustomizedEmployees) и сделать реализацию вычисления. А можно пойти другим путем, через указание запроса (HQL или SQL), как вычислить данную функцию.
Для моего примера c getEmployeesMaxSalary, этот вариант реализации даже проще. Я еще усложню его входным параметром salary. Т.е. достаточно объявить в интерфейсе метод и запрос вычисления.

Упомяну лишь еще, что запросы могут быть и модифицирующие, для этого к ним добавляется еще аннотация @Modifying

Так например в моем гипотетическом примере, когда мне надо для всех сущностей иметь признак “удален», я сделаю базовый интерфейс с методом получения списка объектов с признаком «удален» или «активный»

Далее все репозитории для сущностей можно расширять от него. Интерфейсы которые не являются репозиториями, но находятся в «base-package» папке конфигурации, надо аннотировать @NoRepositoryBean.

Теперь когда будет выполняться запрос, в тело запроса будет подставлено имя сущности T для конкретного репозитория который будет расширять ParentEntityRepository, в данном случае Employees.

Источник

Repository spring что это

The goal of Spring Data repository abstraction is to significantly reduce the amount of boilerplate code required to implement data access layers for various persistence stores.

Spring Data repository documentation and your module

1.1 Core concepts

The central interface in Spring Data repository abstraction is Repository (probably not that much of a surprise). It takes the the domain class to manage as well as the id type of the domain class as type arguments. This interface acts primarily as a marker interface to capture the types to work with and to help you to discover interfaces that extend this one. The CrudRepository provides sophisticated CRUD functionality for the entity class that is being managed.

Example 1.1. CrudRepository interface

repository spring что это. Смотреть фото repository spring что это. Смотреть картинку repository spring что это. Картинка про repository spring что это. Фото repository spring что это

Saves the given entity.

repository spring что это. Смотреть фото repository spring что это. Смотреть картинку repository spring что это. Картинка про repository spring что это. Фото repository spring что это

Returns the entity identified by the given id.

repository spring что это. Смотреть фото repository spring что это. Смотреть картинку repository spring что это. Картинка про repository spring что это. Фото repository spring что это

Returns all entities.

repository spring что это. Смотреть фото repository spring что это. Смотреть картинку repository spring что это. Картинка про repository spring что это. Фото repository spring что это

Returns the number of entities.

repository spring что это. Смотреть фото repository spring что это. Смотреть картинку repository spring что это. Картинка про repository spring что это. Фото repository spring что это

Deletes the given entity.

repository spring что это. Смотреть фото repository spring что это. Смотреть картинку repository spring что это. Картинка про repository spring что это. Фото repository spring что это

Indicates whether an entity with the given id exists.

On top of the CrudRepository there is a PagingAndSortingRepository abstraction that adds additional methods to ease paginated access to entities:

Example 1.2. PagingAndSortingRepository

Accessing the second page of User by a page size of 20 you could simply do something like this:

1.2 Query methods

Standard CRUD functionality repositories usually have queries on the underlying datastore. With Spring Data, declaring those queries becomes a four-step process:

Declare an interface extending Repository or one of its subinterfaces and type it to the domain class that it will handle.

Declare query methods on the interface.

Set up Spring to create proxy instances for those interfaces.

Get the repository instance injected and use it.

The sections that follow explain each step.

1.2.1 Defining repository interfaces

Fine-tuning repository definition

Example 1.3. Selectively exposing CRUD methods

1.2.2 Defining query methods

The repository proxy has two ways to derive a store-specific query from the method name. It can derive the query from the method name directly, or by using an additionally created query. Available options depend on the actual store. However, there’s got to be an strategy that decides what actual query is created. Let’s have a look at the available options.

Query lookup strategies

The following strategies are available for the repository infrastructure to resolve the query. You can configure the strategy at the namespace through the query-lookup-strategy attribute. Some strategies may not be supported for particular datastores.

CREATE

CREATE attempts to construct a store-specific query from the query method name. The general approach is to remove a given set of well-known prefixes from the method name and parse the rest of the method. Read more about query construction in the section called “Query creation”.

USE_DECLARED_QUERY

USE_DECLARED_QUERY tries to find a declared query and will throw an exception in case it can’t find one. The query can be defined by an annotation somewhere or declared by other means. Consult the documentation of the specific store to find available options for that store. If the repository infrastructure does not find a declared query for the method at bootstrap time, it fails.

CREATE_IF_NOT_FOUND (default)

Query creation

Example 1.4. Query creation from method names

The actual result of parsing the method depends on the persistence store for which you create the query. However, there are some general things to notice.

The method parser supports setting an IgnoreCase flag for individual properties, for example, findByLastnameIgnoreCase(…) ) or for all properties of a type that support ignoring case (usually String s, for example, findByLastnameAndFirstnameAllIgnoreCase(…) ). Whether ignoring cases is supported may vary by store, so consult the relevant sections in the reference documentation for the store-specific query method.

You can apply static ordering by appending an OrderBy clause to the query method that references a property and by providing a sorting direction ( Asc or Desc ). To create a query method that supports dynamic sorting, see the section called “Special parameter handling”.

Property expressions

Property expressions can refer only to a direct property of the managed entity, as shown in the preceding example. At query creation time you already make sure that the parsed property is a property of the managed domain class. However, you can also define constraints by traversing nested properties. Assume Person s have Address es with ZipCode s. In that case a method name of

Although this should work for most cases, it is possible for the algorithm to select the wrong property. Suppose the Person class has an addressZip property as well. The algorithm would match in the first split round already and essentially choose the wrong property and finally fail (as the type of addressZip probably has no code property). To resolve this ambiguity you can use _ inside your method name to manually define traversal points. So our method name would end up like so:

Special parameter handling

To handle parameters to your query you simply define method parameters as already seen in the examples above. Besides that the infrastructure will recognize certain specific types like Pageable and Sort to apply pagination and sorting to your queries dynamically.

Example 1.5. Using Pageable and Sort in query methods

The first method allows you to pass an org.springframework.data.domain.Pageable instance to the query method to dynamically add paging to your statically defined query. Sorting options are handled through the Pageable instance too. If you only need sorting, simply add an org.springframework.data.domain.Sort parameter to your method. As you also can see, simply returning a List is possible as well. In this case the additional metadata required to build the actual Page instance will not be created (which in turn means that the additional count query that would have been necessary not being issued) but rather simply restricts the query to look up only the given range of entities.

To find out how many pages you get for a query entirely you have to trigger an additional count query. By default this query will be derived from the query you actually trigger.

1.2.3 Creating repository instances

In this section you create instances and bean definitions for the repository interfaces defined. The easiest way to do so is by using the Spring namespace that is shipped with each Spring Data module that supports the repository mechanism.

XML configuration

Each Spring Data module includes a repositories element that allows you to simply define a base package that Spring scans for you.

Using filters

For example, to exclude certain interfaces from instantiation as repository, you could use the following configuration:

Example 1.6. Using exclude-filter element

This example excludes all interfaces ending in SomeRepository from being instantiated.

JavaConfig

The repository infrastructure can also be triggered using a store-specific @Enable$Repositories annotation on a JavaConfig class. For an introduction into Java-based configuration of the Spring container, see the reference documentation. [1]

A sample configuration to enable Spring Data repositories looks something like this.

Example 1.7. Sample annotation based repository configuration

The sample uses the JPA-specific annotation, which you would change according to the store module you actually use. The same applies to the definition of the EntityManagerFactory bean. Consult the sections covering the store-specific configuration.

Standalone usage

You can also use the repository infrastructure outside of a Spring container. You still need some Spring libraries in your classpath, but generally you can set up repositories programmatically as well. The Spring Data modules that provide repository support ship a persistence technology-specific RepositoryFactory that you can use as follows.

Example 1.8. Standalone usage of repository factory

1.3 Custom implementations for Spring Data repositories

Often it is necessary to provide a custom implementation for a few repository methods. Spring Data repositories easily allow you to provide custom repository code and integrate it with generic CRUD abstraction and query method functionality.

1.3.1 Adding custom behavior to single repositories

To enrich a repository with custom functionality you first define an interface and an implementation for the custom functionality. Use the repository interface you provided to extend the custom interface.

Example 1.9. Interface for custom repository functionality

Example 1.10. Implementation of custom repository functionality

The implementation itself does not depend on Spring Data and can be a regular Spring bean. So you can use standard dependency injection behavior to inject references to other beans, take part in aspects, and so on.

Example 1.11. Changes to the your basic repository interface

Let your standard repository interface extend the custom one. Doing so makes CRUD and custom functionality available to clients.

Configuration

Example 1.12. Configuration example

Manual wiring

The preceding approach works well if your custom implementation uses annotation-based configuration and autowiring only, as it will be treated as any other Spring bean. If your custom implementation bean needs special wiring, you simply declare the bean and name it after the conventions just described. The infrastructure will then refer to the manually defined bean definition by name instead of creating one itself.

Example 1.13. Manual wiring of custom implementations (I)

1.3.2 Adding custom behavior to all repositories

The preceding approach is not feasible when you want to add a single method to all your repository interfaces.

To add custom behavior to all repositories, you first add an intermediate interface to declare the shared behavior.

Example 1.14. An interface declaring custom shared behavior

Now your individual repository interfaces will extend this intermediate interface instead of the Repository interface to include the functionality declared.

Next, create an implementation of the intermediate interface that extends the persistence technology-specific repository base class. This class will then act as a custom base class for the repository proxies.

Example 1.15. Custom repository base class

Example 1.16. Custom repository factory bean

Finally, either declare beans of the custom factory directly or use the factory-class attribute of the Spring namespace to tell the repository infrastructure to use your custom factory implementation.

Example 1.17. Using the custom factory with the namespace

Источник

Разбираемся, как работает Spring Data Repository, и создаем свою библиотеку по аналогии

На habr уже была статья о том, как создать библиотеку в стиле Spring Data Repository (рекомендую к чтению), но способы создания объектов довольно сильно отличаются от «классического» подхода, используемого в Spring Boot. В этой статье я постарался быть максимально близким к этому подходу. Такой способ создания бинов (beans) применяется не только в Spring Data, но и, например, в Spring Cloud OpenFeign.

Содержание

Итак, у нас прошли праздники, но мы хотим иметь возможность создавать на лету бины (beans), которые позволили бы нам поздравлять всех, кого мы в них перечислим.

При вызове метода мы хотим получать:

Т.е. мы должны найти все интерфейсы, которые расширяют интерфейс Congratulator или имеют аннотацию @Congratulate

@Enable

Как и любая взрослая библиотека у нас будет аннотация, которая включает наш механизм (как @EnableFeignClients и @EnableJpaRepositories ).

Напишем свою аннотацию

ImportBeanDefinitionRegistrar

Посмотрим, что происходит в ImportBeanDefinitionRegistrar у Spring Cloud Feign:

В Spring Cloud OpenFeign сначала создаются бины конфигурации, затем выполняется поиск кандидатов и для каждого кандидата создается Factory.

В Spring Data подход аналогичный, но так как Spring Data состоит из множества модулей, то основные моменты разнесены по разным классам (см. например org.springframework.data.repository.config.RepositoryBeanDefinitionBuilder#build )

Можно заметить, что сначала создаются Factory, а не сами bean. Это происходит потому, что мы не можем в BeanDefinitionHolder описать, как должен работать наш bean.

Сделаем по аналогии наш класс (полный код класса можно посмотреть здесь)

ResourceLoaderAware и EnvironmentAware используется для получения объектов класса ResourceLoader и Environment соответственно. При создании экземпляра CongratulatorsRegistrar Spring вызовет соответствующие set-методы.

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

Что, если мы хотим иметь возможность получать наши beans по имени, например, так

это тоже возможно, так как во время создания Factory в качестве alias было передано имя bean ( AnnotationBeanNameGenerator.INSTANCE.generateBeanName(candidateComponent, registry) )

FactoryBean

Теперь займемся Factory.

Стандартный интерфейс FactoryBean имеет 2 метода, которые нужно имплементировать

Заметим, что есть возможность указать, является ли объект, который будет создаваться, Singleton или нет.

Есть абстрактный класс ( AbstractFactoryBean ), который расширяет интерфейс дополнительной логикой (например, поддержка destroy-методов). Он так же имеет 2 абстрактных метода

Второй метод требует вернуть уже сам объект, а для этого нужно его создать. Для этого есть много способов. Здесь представлен один из них.

Сначала создадим обработчик для каждого метода:

Теперь при старте контекста Spring создает бины (beans) на основе наших интерфейсов.

Источник

Spring Data JPA. Пишем DAO и Services. Часть 2

repository spring что это. Смотреть фото repository spring что это. Смотреть картинку repository spring что это. Картинка про repository spring что это. Фото repository spring что это

Шаг 0. Подготовка БД

Не забывайте что мы используем MySQL базу данных, поэтому вам нужно установить MySQL сервер и желательно редактор БД MySQL Workbench. Скачать можно тут.

После установки откройте MySQL Workbench, подключитесь к серверу:

repository spring что это. Смотреть фото repository spring что это. Смотреть картинку repository spring что это. Картинка про repository spring что это. Фото repository spring что это

После, создайте базу данных, нажав по соответствующем значку:

repository spring что это. Смотреть фото repository spring что это. Смотреть картинку repository spring что это. Картинка про repository spring что это. Фото repository spring что это

либо выполнив SQL запрос:

После этого можно переходить к созданию репозиториев. Нам не придётся создавать таблицы в БД их проект создаст сам.

Шаг 1. DAO либо Repository

DAO ( Data Access Object ) – это слой объектов которые обеспечивают доступ к данным.

Обычно для реализации DAO используется EntityManager и с его помощью мы работаем с нашей БД, но в нашем случае это система не подойдет, так как мы изучаем Spring Data нам нужно использовать её средства иначе незачем он нам.

О самом фреймворке Spring Data вы можете почитать тут.

Теперь давайте для каждого Entity создадим Repository, который позволит оперировать объектом в БД.

repository spring что это. Смотреть фото repository spring что это. Смотреть картинку repository spring что это. Картинка про repository spring что это. Фото repository spring что это

Создать Repository довольно просто, даже больше чем просто, давайте создадим для Bank entity его Repository и увидим на сколько все просто:

В 6-й строке видно что мы создали интерфейс с именем BankRepository и унаследовались от JpaRepository.

JpaRepository – это интерфейс фреймворка Spring Data предоставляющий набор стандартных методов JPA для работы с БД.

Ну создали интерфейс и что дальше? Спросите вы. На основе этого интерфейса Spring Data предоставит реализации с методами, которые мы использовали в Entity Manager, немного позже вы увидите пример использования Repository.

Для создания Repository нужно придерживаться несколько правил:

repository spring что это. Смотреть фото repository spring что это. Смотреть картинку repository spring что это. Картинка про repository spring что это. Фото repository spring что это

1 – Имя репозитория должно начинаться с имени сущности NameReposytory (необязательно).

2 – Второй Generic должен быть оберточным типом того типа которым есть ID нашей сущности (обязательно).

3 – Первый Generic должен быть объектом нашей сущности для которой мы создали Repository, это указывает на то, что Spring Data должен предоставить реализацию методов для работы с этой сущностью (обязательно).

4 – Мы должны унаследовать свой интерфейс от JpaRepository, иначе Spring Data не предоставит реализацию для нашего репозитория (обязательно).

Давайте продолжим создание Repositories для других сущностей.

Создаем BankAccountRepositroy для BankAccount:

Создаем ClientRepository для Client:

Создаем WorkerRepository для Worker:

В результате мы получим набор следующих Repositories:

repository spring что это. Смотреть фото repository spring что это. Смотреть картинку repository spring что это. Картинка про repository spring что это. Фото repository spring что это

По сути, теперь у нас есть слой обеспечивающий доступ к данным в БД.

Шаг 2. Создание Services

Service – это Java класс, который предоставляет с себя основную (Бизнес-Логику). В основном сервис использует готовые DAO / Repositories или же другие сервисы, для того чтобы предоставить конечные данные для пользовательского интерфейса.

Давайте создадим пакет service и в нем создадим наш первый сервис который будет предоставлять конечные данные для пользовательского интерфейса.

Я создам сервис для сущности Bank по аналогии делаются другие.

Создаем новый интерфейс BankService :

В этом интерфейс мы указали, какие методы нам будут нужны для написания бизнес-логики проекта.

Теперь создаем в этом же пакете, новый пакет impl в котором будут лежать реализации всех интерфейсов. Структура сервиса и его реализации:

repository spring что это. Смотреть фото repository spring что это. Смотреть картинку repository spring что это. Картинка про repository spring что это. Фото repository spring что это

Давайте создадим BankServiceImpl который будет реализовывать BankService интерфейс:

Теперь разберем, что же мы тут написали:

14 строка – это аннотация которая позволит Spring инициализировать наш сервис;

15 строка – объявление нашего сервиса (обратите внимание, что это интерфейс, а не реализация), который позволит нам использовать его бизнес-логику;

19 строка – тут мы сохраняем Bank в БД используя метод saveAndFlush, используя просто save() мы сохраняем запись но после вызова flush данные попадают в БД;

26 строка – удаление Bank по его id;

31 строка – этот метод не предоставляется Spring Data в следующем шаге мы рассмотрим как его сделать;

36 строка – update можно сделать тем же методом что и сохранение, так как hibernate умный, и он проверит, есть ли запись в БД, которую мы хотим сохранить, если есть, то он её обновит;

41 строка – получаем все данные с БД, а именно все банки.

Шаг 3. Кастомный метод в Spring Data

И так, в реализации BankService есть метод getByName(), который должен получать Bank по имени, в стандартных средствах Spring Data нет такой возможности, поэтому мы напишем свой кастомный метод.

Для этого зайдите в интерфейс BankRepository и там напишите следующий метод:

В строке 3 мы используем аннотацию @Query которая позволяет создать SQL запрос, но этот запрос содержит параметр :name, его иы проставляем в структуре метода findByName() используя аннотация @Param в параметре которой мы указываем имя параметра запроса name.

Spring Data на основе предоставленных данных в аннотациях сам предоставит реализацию этого метода, и это замечательно, так как теперь мы его можем использовать:

И вот финальная структура проекта:

repository spring что это. Смотреть фото repository spring что это. Смотреть картинку repository spring что это. Картинка про repository spring что это. Фото repository spring что это

Смотрите в следующем уроке, как тестировать Сервисы:

На этом все, качайте исходники в начале урока, разбирайтесь, если что-то непонятно, то все вопросы в комментарии.

Источник

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *