Repository spring что это

Spring Data на примере JPA

Введение

Spring Data позволяет легче создавать Spring-управляемые приложения которые используют новые способы доступа к данным, например нереляционные базы данных, map-reduce фреймворки, cloud сервисы, а так же уже хорошо улучшенную поддердку реляционных баз данных.

В этой статье будет рассмотрен один из под-проектов Spring Data — JPA

Что может Spring Data — JPA
Для чего вам может понадобиться Spring Data — JPA

Я бы ответил так — если вам нужно быстро в проекте создать Repository слой базируемый на JPA, предназначенный в основном для CRUD операций, и вы не хотите создавать абстрактные дао, интерфейсы их реализации, то Spring Data — JPA это хороший выбор.

С чего начать

Будем считать у вас уже есть maven проект с подключенным Spring, базой данных, настроенным EntityManager-ом.

1. Добавьте артефакт со Spring Data — JPA

2. В ваш applicationContext.xml нужно добавить путь где будут храниться ваши Repository интерфейсы

3. Создать Entity и Repository интерфейс для него

4. Теперь вы можете использовать созданный интерфейс в вашем приложении

Наследовавшись от CrudRepository вы получили возможность вызывать такие методы как:

без необходимости реализовывать их имплементацию.

Работа с запросами, сортировкой, порционной загрузкой

Рассмотрим на примере: вам нужно сделать запрос, который выберет все Test записи, у которых поле «dummy» установленно в false, и записи отсортированны по полю «tries» в порядке ABC.

Для решения такой задачи вы можете выбрать один из нескольких вариантов:

Если с первым способом все предельно просто и это знакомый запрос, то второй способ заключается в том, чтобы составить имя метода, особым способом использую ключевые слова, такие как: «find», «order», имя переменных и тд. Разработчики Spring Data — JPA постарались учесть большинство возможных вариантов, которые могут вам понадобится.

Specification и CriteriaBuilder

Если вам нужно написать действительно сложный запрос для этого вы можете использовать Specification.
Пример в котором в зависимости от «retries» будут выбраны данные с разными значениями «dummy».

Следующий пример покажет как можно использовать созданный Specification для фильтра всех данных.
Расширим ваш интерфейс при помощи JpaSpecificationExecutor

и вызовем метод findAll передав ему созданную Specification

Источник

Разбираемся, как работает 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) на основе наших интерфейсов.

Источник

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 что это. 1. Repository spring что это фото. Repository spring что это-1. картинка Repository spring что это. картинка 1

Saves the given entity.

Repository spring что это. 2. Repository spring что это фото. Repository spring что это-2. картинка Repository spring что это. картинка 2

Returns the entity identified by the given id.

Repository spring что это. 3. Repository spring что это фото. Repository spring что это-3. картинка Repository spring что это. картинка 3

Returns all entities.

Repository spring что это. 4. Repository spring что это фото. Repository spring что это-4. картинка Repository spring что это. картинка 4

Returns the number of entities.

Repository spring что это. 5. Repository spring что это фото. Repository spring что это-5. картинка Repository spring что это. картинка 5

Deletes the given entity.

Repository spring что это. 6. Repository spring что это фото. Repository spring что это-6. картинка Repository spring что это. картинка 6

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 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 что это. image loader. Repository spring что это фото. Repository spring что это-image loader. картинка Repository spring что это. картинка image loader
Достаточно только определить подобным образом метод, без имплементации и 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 JPA module of Spring Data contains a custom namespace that allows defining repository beans. It also contains certain features and element attributes that are special to JPA. Generally the JPA repositories can be set up using the repositories element:

Example 2.1. Setting up JPA repositories using the namespace

Using this element looks up Spring Data repositories as described in Section 1.2.3, “Creating repository instances”. Beyond that it activates persistence exception translation for all beans annotated with @Repository to let exceptions being thrown by the JPA persistence providers be converted into Spring’s DataAccessException hierarchy.

Custom namespace attributes

Beyond the default attributes of the repositories element the JPA namespace offers additional attributes to gain more detailed control over the setup of the repositories:

Table 2.1. Custom JPA-specific attributes of the repositories element

Note that we require a PlatformTransactionManager bean named transactionManager to be present if no explicit transaction-manager-ref is defined.

2.1.2 Annotation based configuration

The Spring Data JPA repositories support cannot only be activated through an XML namespace but also using an annotation through JavaConfig.

Example 2.2. Spring Data JPA repositories using JavaConfig

2.2 Persisting entities

2.2.1 Saving entities

Entity state detection strategies

Spring Data JPA offers the following strategies to detect whether an entity is new or not:

Table 2.2. Options for detection whether an entity is new in Spring Data JPA

2.3 Query methods

2.3.1 Query lookup strategies

The JPA module supports defining a query manually as String or have it being derived from the method name.

Declared queries

Although getting a query derived from the method name is quite convenient, one might face the situation in which either the method name parser does not support the keyword one wants to use or the method name would get unnecessarily ugly. So you can either use JPA named queries through a naming convention (see Section 2.3.3, “Using JPA NamedQueries” for more information) or rather annotate your query method with @Query (see Section 2.3.4, “Using @Query” for details).

2.3.2 Query creation

Generally the query creation mechanism for JPA works as described in Section 1.2, “Query methods”. Here’s a short example of what a JPA query method translates into:

Example 2.3. Query creation from method names

We will create a query using the JPA criteria API from this but essentially this translates into the following query:

Table 2.3. Supported keywords inside method names

In and NotIn also take any subclass of Collection as parameter as well as arrays or varargs. For other syntactical versions of the very same logical operator check Appendix B, Repository query keywords.

2.3.3 Using JPA NamedQueries

The examples use simple element and @NamedQuery annotation. The queries for these configuration elements have to be defined in JPA query language. Of course you can use or @NamedNativeQuery too. These elements allow you to define the query in native SQL by losing the database platform independence.

XML named query definition

To use XML configuration simply add the necessary element to the orm.xml JPA configuration file located in META-INF folder of your classpath. Automatic invocation of named queries is enabled by using some defined naming convention. For more details see below.

Example 2.4. XML named query configuration

As you can see the query has a special name which will be used to resolve it at runtime.

Annotation configuration

Annotation configuration has the advantage of not needing another configuration file to be edited, probably lowering maintenance costs. You pay for that benefit by the need to recompile your domain class for every new query declaration.

Example 2.5. Annotation based named query configuration

Declaring interfaces

To allow execution of these named queries all you need to do is to specify the UserRepository as follows:

Example 2.6. Query method declaration in UserRepository

Spring Data will try to resolve a call to these methods to a named query, starting with the simple name of the configured domain class, followed by the method name separated by a dot. So the example here would use the named queries defined above instead of trying to create a query from the method name.

2.3.4 Using @Query

Using named queries to declare queries for entities is a valid approach and works fine for a small number of queries. As the queries themselves are tied to the Java method that executes them you actually can bind them directly using the Spring Data JPA @Query annotation rather than annotating them to the domain class. This will free the domain class from persistence specific information and co-locate the query to the repository interface.

Example 2.7. Declare query at the query method using @Query

Using advanced LIKE expressions

The query execution mechanism for manually defined queries using @Query allow the definition of advanced LIKE expressions inside the query definition.

Example 2.8. Advanced LIKE expressions in @Query

In the just shown sample LIKE delimiter character % is recognized and the query transformed into a valid JPQL query (removing the % ). Upon query execution the parameter handed into the method call gets augmented with the previously recognized LIKE pattern.

Native queries

The @Query annotation allows to execute native queries by setting the nativeQuery flag to true. Note, that we currently don’t support execution of pagination or dynamic sorting for native queries as we’d have to manipulate the actual query declared and we cannot do this reliably for native SQL.

Example 2.9. Declare a native query at the query method using @Query

2.3.5 Using named parameters

By default Spring Data JPA will use position based parameter binding as described in all the samples above. This makes query methods a little error prone to refactoring regarding the parameter position. To solve this issue you can use @Param annotation to give a method parameter a concrete name and bind the name in the query.

Example 2.10. Using named parameters

Note that the method parameters are switched according to the occurrence in the query defined.

2.3.6 Using SpEL expressions

Table 2.4. Supported variables inside SpEL based query templates

VariableUsageDescription
entityNameselect x from # <#entityName>xInserts the entityName of the domain type associated with the given Repository. The entityName is resolved as follows: If the domain type has set the name property on the @Entity annotation then it will be used. Otherwise the simple class-name of the domain type will be used.

The following example demonstrates one use case for the # <#entityName>expression in a query string where you want to define a repository interface with a query method with a manually defined query. In order not to have to state the actual entity name in the query string of a @Query annotation one can use the # <#entityName>Variable.

Another use case for the # <#entityName>expression in a query string is if you want to define a generic repository interface with specialized repository interfaces for a concrete domain type. In order not to have to repeat the definition of custom query methods on the concrete interfaces you can use the entity name expression in the query string of the @Query annotation in the generic repository interface.

2.3.7 Modifying queries

All the sections above describe how to declare queries to access a given entity or collection of entities. Of course you can add custom modifying behaviour by using facilities described in Section 1.3, “Custom implementations for Spring Data repositories”. As this approach is feasible for comprehensive custom functionality, you can achieve the execution of modifying queries that actually only need parameter binding by annotating the query method with @Modifying :

Example 2.13. Declaring manipulating queries

2.3.8 Applying query hints

To apply JPA QueryHint s to the queries declared in your repository interface you can use the QueryHints annotation. It takes an array of JPA QueryHint annotations plus a boolean flag to potentially disable the hints applied to the addtional count query triggered when applying pagination.

Example 2.14. Using QueryHints with a repository method

The just shown declaration would apply the configured QueryHint for that actually query but omit applying it to the count query triggered to calculate the total number of pages.

2.4 Specifications

JPA 2 introduces a criteria API that can be used to build queries programmatically. Writing a criteria you actually define the where-clause of a query for a domain class. Taking another step back these criteria can be regarded as predicate over the entity that is described by the JPA criteria API constraints.

Spring Data JPA takes the concept of a specification from Eric Evans’ book «Domain Driven Design», following the same semantics and providing an API to define such Specification s using the JPA criteria API. To support specifications you can extend your repository interface with the JpaSpecificationExecutor interface:

The additional interface carries methods that allow you to execute Specification s in a variety of ways.

For example, the findAll method will return all entities that match the specification:

The Specification interface is as follows:

Okay, so what is the typical use case? Specification s can easily be used to build an extensible set of predicates on top of an entity that then can be combined and used with JpaRepository without the need to declare a query (method) for every needed combination. Here’s an example:

Example 2.15. Specifications for a Customer

Example 2.16. Using a simple Specification

Okay, why not simply create a query for this kind of data access? You’re right. Using a single Specification does not gain a lot of benefit over a plain query declaration. The power of Specification s really shines when you combine them to create new Specification objects. You can achieve this through the Specifications helper class we provide to build expressions like this:

Example 2.17. Combined Specifications

As you can see, Specifications offers some glue-code methods to chain and combine Specification s. Thus extending your data access layer is just a matter of creating new Specification implementations and combining them with ones already existing.

2.5 Transactionality

Example 2.18. Custom transaction configuration for CRUD

This will cause the findAll() method to be executed with a timeout of 10 seconds and without the readOnly flag.

Another possibility to alter transactional behaviour is using a facade or service implementation that typically covers more than one repository. Its purpose is to define transactional boundaries for non-CRUD operations:

Example 2.19. Using a facade to define transactions for multiple repository calls

This will cause call to addRoleToAllUsers(…) to run inside a transaction (participating in an existing one or create a new one if none already running). The transaction configuration at the repositories will be neglected then as the outer transaction configuration determines the actual one used. Note that you will have to activate or use @EnableTransactionManagement explicitly to get annotation based configuration at facades working. The example above assumes you are using component scanning.

2.5.1 Transactional query methods

To allow your query methods to be transactional simply use @Transactional at the repository interface you define.

Example 2.20. Using @Transactional at query methods

Typically you will want the readOnly flag set to true as most of the query methods will only read data. In contrast to that deleteInactiveUsers() makes use of the @Modifying annotation and overrides the transaction configuration. Thus the method will be executed with readOnly flag set to false.

It’s definitely reasonable to use transactions for read only queries and we can mark them as such by setting the readOnly flag. This will not, however, act as check that you do not trigger a manipulating query (although some databases reject INSERT and UPDATE statements inside a read only transaction). The readOnly flag instead is propagated as hint to the underlying JDBC driver for performance optimizations. Furthermore, Spring will perform some optimizations on the underlying JPA provider. E.g. when used with Hibernate the flush mode is set to NEVER when you configure a transaction as readOnly which causes Hibernate to skip dirty checks (a noticeable improvement on large object trees).

2.6 Locking

To specify the lock mode to be used the @Lock annotation can be used on query methods:

Example 2.21. Defining lock metadata on query methods

Example 2.22. Defining lock metadata on CRUD methods

2.7 Auditing

2.7.1 Basics

Spring Data provides sophisticated support to transparently keep track of who created or changed an entity and the point in time this happened. To benefit from that functionality you have to equip your entity classes with auditing metadata that can be defined either using annotations or by implementing an interface.

Annotation based auditing metadata

Example 2.23. An audited entity

Interface-based auditing metadata

In case you don’t want to use annotations to define auditing metadata you can let your domain class implement the Auditable interface. It exposes setter methods for all of the auditing properties.

There’s also a convenience base class AbstractAuditable which you can extend to avoid the need to manually implement the interface methods. Be aware that this increases the coupling of your domain classes to Spring Data which might be something you want to avoid. Usually the annotation based way of defining auditing metadata is preferred as it is less invasive and more flexible.

AuditorAware

Here’s an example implementation of the interface using Spring Security’s Authentication object:

Example 2.24. Implementation of AuditorAware based on Spring Security

The implementation is accessing the Authentication object provided by Spring Security and looks up the custom UserDetails instance from it that you have created in your UserDetailsService implementation. We’re assuming here that you are exposing the domain user through that UserDetails implementation but you could also look it up from anywhere based on the Authentication found.

2.7.2 General auditing configuration

Spring Data JPA ships with an entity listener that can be used to trigger capturing auditing information. So first you have to register the AuditingEntityListener inside your orm.xml to be used for all entities in your persistence contexts:

Note that the auditing feature requires spring-aspects.jar to be on the classpath.

Example 2.25. Auditing configuration orm.xml

Now activating auditing functionality is just a matter of adding the Spring Data JPA auditing namespace element to your configuration:

Example 2.26. Activating auditing using XML configuration

As of Spring Data JPA 1.5, auditing can be enabled by annotating a configuration class with the @EnableJpaAuditing annotation.

Example 2.27. Activating auditing via Java configuration

2.8 Miscellaneous

2.8.1 Merging persistence units

Spring supports having multiple persistence units out of the box. Sometimes, however, you might want to modularize your application but still make sure that all these modules run inside a single persistence unit at runtime. To do so Spring Data JPA offers a PersistenceUnitManager implementation that automatically merges persistence units based on their name.

Example 2.28. Using MergingPersistenceUnitmanager

2.8.2 Classpath scanning for @Entity classes and JPA mapping files

Example 2.29. Using ClasspathScanningPersistenceUnitPostProcessor

As of Spring 3.1 a package to scan can be configured on the LocalContainerEntityManagerFactoryBean directly to enable classpath scanning for entity classes. See the JavaDoc for details.

2.8.3 CDI integration

Instances of the repository interfaces are usually created by a container, which Spring is the most natural choice when working with Spring Data. There’s sophisticated support to easily set up Spring to create bean instances documented in Section 1.2.3, “Creating repository instances”. As of version 1.1.0 Spring Data JPA ships with a custom CDI extension that allows using the repository abstraction in CDI environments. The extension is part of the JAR so all you need to do to activate it is dropping the Spring Data JPA JAR into your classpath.

You can now set up the infrastructure by implementing a CDI Producer for the EntityManagerFactory and EntityManager :

The necessary setup can vary depending on the JavaEE environment you run in. It might also just be enough to redeclare a EntityManager as CDI bean as follows:

In this example, the container has to be capable of creating JPA EntityManager s itself. All the configuration does is re-exporting the JPA EntityManager as CDI bean.

The Spring Data JPA CDI extension will pick up all EntityManager s availables as CDI beans and create a proxy for a Spring Data repository whenever an bean of a repository type is requested by the container. Thus obtaining an instance of a Spring Data repository is a matter of declaring an @Inject ed property:

Источник

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

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