1. Обзор
Эта статья представляет собой введение в Spring Data Neo4j , популярную графовую базу данных.
Spring Data Neo4j обеспечивает разработку на основе POJO для базы данных Neo4j Graph и использует знакомые концепции Spring, такие как классы шаблонов для использования основного API, и предоставляет модель программирования на основе аннотаций.
Кроме того, многие разработчики на самом деле не знают, действительно ли Neo4j подойдет для их конкретных нужд; вот солидный обзор Stackoverflow, в котором обсуждается, зачем использовать Neo4j, а также плюсы и минусы.
2. Зависимости Maven
Начнем с объявления зависимостей Spring Data Neo4j в файле pom.xml.
Упомянутые ниже модули Spring также необходимы для Spring Data Neo4j:
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-neo4j</artifactId>
<version>5.0.1.RELEASE</version>
</dependency>
<dependency>
<groupId>org.neo4j</groupId>
<artifactId>neo4j-ogm-test</artifactId>
<version>3.1.2</version>
<scope>test</scope>
</dependency>
Эти зависимости также включают в себя необходимые модули для тестирования.
Обратите внимание, что последняя зависимость имеет область действия «тест». Но также обратите внимание, что при разработке приложений в реальном мире у вас, скорее всего, будет работать полноценный сервер Neo4J.
Если мы хотим использовать встроенный сервер, мы также должны добавить зависимость:
<dependency>
<groupId>org.neo4j</groupId>
<artifactId>neo4j-ogm-embedded-driver</artifactId>
<version>3.1.2</version>
</dependency>
Зависимости spring-data-neo4j , neo4j-ogm-test и neo4j-ogm-embedded-driver доступны на Maven Central.
3. Конфигурация Neo4Jj
Конфигурация Neo4j очень проста и определяет параметры подключения приложения для подключения к серверу. Подобно большинству других модулей данных Spring, это конфигурация Spring, которую можно определить как конфигурацию XML или Java.
В этом руководстве мы будем использовать только конфигурацию на основе Java:
public static final String URL =
System.getenv("NEO4J_URL") != null ?
System.getenv("NEO4J_URL") : "http://neo4j:movies@localhost:7474";
@Bean
public org.neo4j.ogm.config.Configuration getConfiguration() {
return new Builder().uri(URL).build();
}
@Bean
public SessionFactory getSessionFactory() {
return new SessionFactory(getConfiguration(),
"com.foreach.spring.data.neo4j.domain");
}
@Bean
public Neo4jTransactionManager transactionManager() {
return new Neo4jTransactionManager(getSessionFactory());
}
Как было сказано выше, конфиг простой и содержит всего две настройки. Во-первых, SessionFactory
ссылается на модели, которые мы создали для представления объектов данных. Затем свойства соединения с конечными точками сервера и учетными данными для доступа.
Neo4j выведет класс драйвера на основе протокола URI, в нашем случае «http».
Обратите внимание, что в этом примере свойства, связанные с подключением, настраиваются непосредственно на сервере; однако в рабочем приложении они должны быть должным образом экстернализованы и являться частью стандартной конфигурации проекта.
4. Репозитории Neo4j
В соответствии с платформой Spring Data, Neo4j поддерживает поведение абстракции репозитория Spring Data. Это означает, что доступ к базовому персистентному механизму абстрагируется во встроенном репозитории Neo4jRepository
, где проект может напрямую расширять его и использовать предоставленные операции «из коробки».
Репозитории расширяемы с помощью аннотированных, именованных или производных методов поиска. Поддержка репозиториев Spring Data Neo4j также основана на Neo4jTemplate
, поэтому базовая функциональность идентична.
4.1. Создание MovieRepository
и PersonRepository
В этом руководстве мы используем два репозитория для сохранения данных:
@Repository
public interface MovieRepository extends Neo4jRepository<Movie, Long> {
Movie findByTitle(@Param("title") String title);
@Query("MATCH (m:Movie) WHERE m.title =~ ('(?i).*'+{title}+'.*') RETURN m")
Collection<Movie>
findByTitleContaining(@Param("title") String title);
@Query("MATCH (m:Movie)<-[:ACTED_IN]-(a:Person)
RETURN m.title as movie, collect(a.name) as cast LIMIT {limit}")
List<Map<String,Object>> graph(@Param("limit") int limit);
}
Как видите, репозиторий содержит некоторые пользовательские операции, а также стандартные, унаследованные от базового класса.
Далее у нас есть более простой PersonRepository
, в котором есть только стандартные операции:
@Repository
public interface PersonRepository extends Neo4jRepository <Person, Long> {
//
}
Возможно, вы уже заметили, что PersonRepository
— это просто стандартный интерфейс Spring Data. Это связано с тем, что в этом простом примере почти достаточно использовать встроенные операции, поскольку наш набор операций связан с сущностью Movie .
Однако вы всегда можете добавить сюда пользовательские операции, которые могут заключать в себе одну или несколько встроенных операций.
4.2. Настройка репозиториев Neo4j
В качестве следующего шага мы должны сообщить Spring соответствующий репозиторий, указав его в классе Neo4jConfiguration
, созданном в разделе 3:
@Configuration
@ComponentScan("com.foreach.spring.data.neo4j")
@EnableNeo4jRepositories(
basePackages = "com.foreach.spring.data.neo4j.repository")
public class MovieDatabaseNeo4jConfiguration {
//
}
5. Полная модель данных
Мы уже начали рассматривать модель данных, так что давайте теперь все это выложим — полное Movie, Role
и Person
. Сущность Person
ссылается на сущность Movie
через отношение Role
.
@NodeEntity
public class Movie {
@Id @GeneratedValue
Long id;
private String title;
private int released;
private String tagline;
@Relationship(type="ACTED_IN", direction = Relationship.INCOMING)
private List<Role> roles;
// standard constructor, getters and setters
}
Обратите внимание, как мы аннотировали Movie
с помощью @NodeEntity
, чтобы указать, что этот класс напрямую сопоставлен с узлом в Neo4j.
@JsonIdentityInfo(generator=JSOGGenerator.class)
@NodeEntity
public class Person {
@Id @GeneratedValue
Long id;
private String name;
private int born;
@Relationship(type = "ACTED_IN")
private List<Movie> movies;
// standard constructor, getters and setters
}
@JsonIdentityInfo(generator=JSOGGenerator.class)
@RelationshipEntity(type = "ACTED_IN")
public class Role {
@Id @GeneratedValue
Long id;
private Collection<String> roles;
@StartNode
private Person person;
@EndNode
private Movie movie;
// standard constructor, getters and setters
}
Конечно, эти последние два класса аннотированы аналогичным образом, а ссылка -movies –
связывает класс Person
с Movie
отношением «ACTED_IN».
6. Доступ к данным с помощью MovieRepository
6.1. Сохранение нового объекта фильма
Давайте сохраним некоторые данные — сначала новый фильм, затем человека и, конечно же, роль — включая все данные отношений, которые у нас есть:
Movie italianJob = new Movie();
italianJob.setTitle("The Italian Job");
italianJob.setReleased(1999);
movieRepository.save(italianJob);
Person mark = new Person();
mark.setName("Mark Wahlberg");
personRepository.save(mark);
Role charlie = new Role();
charlie.setMovie(italianJob);
charlie.setPerson(mark);
Collection<String> roleNames = new HashSet();
roleNames.add("Charlie Croker");
charlie.setRoles(roleNames);
List<Role> roles = new ArrayList();
roles.add(charlie);
italianJob.setRoles(roles);
movieRepository.save(italianJob);
6.2. Получение существующего объекта фильма по заголовку
Давайте теперь проверим вставленный фильм, извлекая его с помощью определенного заголовка, который является пользовательской операцией:
Movie result = movieRepository.findByTitle(title);
6.3. Извлечение существующего кинообъекта по части заголовка
Возможен поиск для поиска существующего фильма по части названия:
Collection<Movie> result = movieRepository.findByTitleContaining("Italian");
6.4. Получение всех фильмов
Все фильмы можно получить один раз и проверить правильность подсчета:
Collection<Movie> result = (Collection<Movie>) movieRepository.findAll();
Однако существует ряд методов поиска с поведением по умолчанию, которые полезны для таможенных требований, и не все они описаны здесь.
6.5. Подсчитайте существующие кинообъекты
После вставки нескольких объектов фильма мы можем получить количество выходящих фильмов:
long movieCount = movieRepository.count();
6.6. Удаление существующего фильма
movieRepository.delete(movieRepository.findByTitle("The Italian Job"));
После удаления вставленного фильма мы можем найти объект фильма и убедиться, что результат равен нулю:
assertNull(movieRepository.findByTitle("The Italian Job"));
6.7. Удалить все вставленные данные
Можно удалить все элементы в базе данных, сделав базу данных пустой:
movieRepository.deleteAll();
Результат этой операции быстро удаляет все данные из таблицы.
7. Заключение
В этом уроке мы рассмотрели основы Spring Data Neo4j на очень простом примере.
Однако Neo4j способен обслуживать очень продвинутые и сложные приложения, имеющие огромный набор связей и сетей. И Spring Data Neo4j также предлагает расширенные функции для сопоставления аннотированных классов сущностей с базой данных Neo4j Graph.
Реализацию приведенных выше фрагментов кода и примеры можно найти в проекте GitHub — это проект на основе Maven, поэтому его легко импортировать и запускать как есть.