Рубрики
Без рубрики

Составные хранилища данных Spring

Узнайте, как использовать несколько фрагментов для реализации хранилища данных Spring

Автор оригинала: baeldung.

1. введение

При моделировании реальной системы или процесса хорошим вариантом являются репозитории в стиле доменного проектирования (DDD). Именно для этой цели мы можем использовать Spring Data JPA в качестве уровня абстракции доступа к данным.

Если вы новичок в этой концепции, ознакомьтесь с этим вводным руководством, которое поможет вам войти в курс дела.

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

2. Зависимости Maven

Возможность создания составных репозиториев доступна начиная с весны 5.

Давайте добавим необходимую зависимость для Spring Data JPA:


    org.springframework.data
    spring-data-jpa
    2.2.2.RELEASE

Нам также нужно будет настроить источник данных, чтобы наш уровень доступа к данным работал. Это хорошая идея-создать базу данных в памяти, такую как H2, для разработки и быстрого тестирования.

3. Предыстория

3.1. Спящий режим как реализация JPA

Spring Data JPA по умолчанию использует Hibernate в качестве реализации JPA. Мы можем легко спутать одно с другим или сравнить их, но они служат разным целям.

Spring Data JPA-это уровень абстракции доступа к данным, ниже которого мы можем использовать любую реализацию. Мы могли бы, например, отключить режим гибернации в пользу EclipseLink .

3.2. Репозитории по умолчанию

Во многих случаях нам не нужно было бы самим писать какие-либо запросы.

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

public interface LocationRepository extends JpaRepository {
}

И это само по себе позволило бы нам выполнять общие операции – CRUD, подкачка и сортировка – на объекте Location , который имеет первичный ключ типа Long .

Кроме того, Spring Data JPA оснащен механизмом построения запросов, который обеспечивает возможность генерировать запросы от нашего имени, используя соглашения об именах методов:

public interface StoreRepository extends JpaRepository {
    List findStoreByLocationId(Long locationId);
}

3.3. Пользовательские репозитории

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

Например, здесь мы обогащаем наш Репозиторий типов элементов путем расширения репозитория фрагментов:

public interface ItemTypeRepository 
  extends JpaRepository, CustomItemTypeRepository {
}

Здесь CustomItemTypeRepository это другой интерфейс:

public interface CustomItemTypeRepository {
    void deleteCustomById(ItemType entity);
}

Его реализация может быть хранилищем любого типа, а не только JPA:

public class CustomItemTypeRepositoryImpl implements CustomItemTypeRepository {
 
    @Autowired
    private EntityManager entityManager;

    @Override
    public void deleteCustomById(ItemType itemType) {
        entityManager.remove(itemType);
    }
}

Нам просто нужно убедиться, что у него есть постфикс Impl . Однако мы можем установить пользовательский постфикс, используя следующую конфигурацию XML:

или с помощью этой аннотации:

@EnableJpaRepositories(
  basePackages = "com.baeldung.repository", repositoryImplementationPostfix = "CustomImpl")

4. Создание Репозиториев С Использованием Нескольких Фрагментов

До нескольких выпусков назад мы могли расширять наши интерфейсы репозитория только с помощью одной пользовательской реализации. Это было ограничение, из-за которого нам пришлось бы объединить все связанные функции в один объект.

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

Теперь, с весной 5, у нас есть возможность обогатить наш репозиторий JPA несколькими репозиториями фрагментов . Опять же, остается требование, чтобы у нас были эти фрагменты в виде пар интерфейс-реализация.

Чтобы продемонстрировать это, давайте создадим два фрагмента:

public interface CustomItemTypeRepository {
    void deleteCustom(ItemType entity);
    void findThenDelete(Long id);
}

public interface CustomItemRepository {
    Item findItemById(Long id);
    void deleteCustom(Item entity);
    void findThenDelete(Long id);
}

Конечно, нам нужно было бы написать их реализации. Но вместо того, чтобы подключать эти пользовательские репозитории – со связанными функциями – в их собственные репозитории JPA, мы можем расширить функциональность одного репозитория JPA:

public interface ItemTypeRepository 
  extends JpaRepository, CustomItemTypeRepository, CustomItemRepository {
}

Теперь у нас будет вся связанная функциональность в одном репозитории.

5. Работа с двусмысленностью

Поскольку мы наследуем от нескольких репозиториев, у нас могут возникнуть проблемы с определением того, какая из наших реализаций будет использоваться в случае столкновения. Например, в нашем примере оба хранилища фрагментов имеют метод find Then Delete () с одинаковой сигнатурой.

В этом сценарии порядок объявления интерфейсов используется для устранения неоднозначности . Следовательно, в нашем случае метод внутри Репозитория пользовательских типов элементов будет использоваться с момента его объявления первым.

Мы можем проверить это с помощью этого тестового случая:

@Test
public void givenItemAndItemTypeWhenDeleteThenItemTypeDeleted() {
    Optional itemType = composedRepository.findById(1L);
    assertTrue(itemType.isPresent());

    Item item = composedRepository.findItemById(2L);
    assertNotNull(item);

    composedRepository.findThenDelete(1L);
    Optional sameItemType = composedRepository.findById(1L);
    assertFalse(sameItemType.isPresent());

    Item sameItem = composedRepository.findItemById(2L);
    assertNotNull(sameItem);
}

6. Заключение

В этой статье мы рассмотрели различные способы, с помощью которых мы можем использовать репозитории Spring Data JPA. Мы видели, что Spring упрощает выполнение операций с базами данных над объектами нашего домена без написания большого количества кода или даже SQL-запросов.

Эта поддержка значительно настраивается за счет использования составных репозиториев.

Фрагменты кода из этой статьи доступны в качестве проекта Maven здесь, на GitHub .