Перейти к основному содержимому

Введение в Spring Data Couchbase

· 8 мин. чтения

1. Введение

В этом руководстве по Spring Data мы обсудим, как настроить уровень сохраняемости для документов Couchbase, используя как репозиторий Spring Data, так и абстракции шаблонов, а также шаги, необходимые для подготовки Couchbase для поддержки этих абстракций с использованием представлений и/или индексов. .

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

Во-первых, мы добавляем следующую зависимость Maven в наш файл pom.xml :

<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-couchbase</artifactId>
<version>2.0.0.RELEASE</version>
</dependency>

Обратите внимание, что, включая эту зависимость, мы автоматически получаем совместимую версию собственного Couchbase SDK, поэтому нам не нужно включать ее явно.

Чтобы добавить поддержку проверки bean-компонентов JSR-303, мы также включаем следующую зависимость:

<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>5.2.4.Final</version>
</dependency>

Spring Data Couchbase поддерживает сохранение даты и времени с помощью традиционных классов Date и Calendar, а также с помощью библиотеки Joda Time, которую мы включаем следующим образом:

<dependency>
<groupId>joda-time</groupId>
<artifactId>joda-time</artifactId>
<version>2.9.2</version>
</dependency>

3. Конфигурация

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

3.1. Конфигурация Java

Для конфигурации класса Java мы просто расширяем класс AbstractCouchbaseConfiguration :

@Configuration
@EnableCouchbaseRepositories(basePackages={"com.foreach.spring.data.couchbase"})
public class MyCouchbaseConfig extends AbstractCouchbaseConfiguration {

@Override
protected List<String> getBootstrapHosts() {
return Arrays.asList("localhost");
}

@Override
protected String getBucketName() {
return "foreach";
}

@Override
protected String getBucketPassword() {
return "";
}
}

Если ваш проект требует дополнительной настройки среды Couchbase, вы можете предоставить ее, переопределив метод getEnvironment() :

@Override
protected CouchbaseEnvironment getEnvironment() {
...
}

3.2. XML-конфигурация

Вот эквивалентная конфигурация в XML:

<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.springframework.org/schema/data/couchbase
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/data/couchbase
http://www.springframework.org/schema/data/couchbase/spring-couchbase.xsd">

<couchbase:cluster>
<couchbase:node>localhost</couchbase:node>
</couchbase:cluster>

<couchbase:clusterInfo login="foreach" password="" />

<couchbase:bucket bucketName="foreach" bucketPassword=""/>

<couchbase:repositories base-package="com.foreach.spring.data.couchbase"/>
</beans:beans>

Примечание: узел « clusterInfo » принимает либо учетные данные кластера, либо учетные данные корзины и необходим для того, чтобы библиотека могла определить, поддерживает ли ваш кластер Couchbase N1QL (расширенный набор SQL для баз данных NoSQL, доступный в Couchbase 4.0 и более поздних версиях).

Если для вашего проекта требуется пользовательская среда Couchbase, вы можете предоставить ее с помощью тега <couchbase:env/> .

4. Модель данных

Давайте создадим класс сущности, представляющий документ JSON для сохранения. Сначала мы аннотируем класс с помощью @Document, а затем аннотируем поле String с помощью @Id для представления ключа документа Couchbase.

Вы можете использовать либо аннотацию @Id из Spring Data, либо аннотацию из собственного Couchbase SDK. Имейте в виду, что если вы используете обе аннотации @Id в одном классе в двух разных полях, то поле, аннотированное аннотацией Spring Data @Id , будет иметь приоритет и будет использоваться в качестве ключа документа.

Чтобы представить атрибуты документов JSON, мы добавляем закрытые переменные-члены, аннотированные @Field . Мы используем аннотацию @NotNull , чтобы пометить определенные поля как обязательные:

@Document
public class Person {
@Id
private String id;

@Field
@NotNull
private String firstName;

@Field
@NotNull
private String lastName;

@Field
@NotNull
private DateTime created;

@Field
private DateTime updated;

// standard getters and setters
}

Обратите внимание, что свойство, аннотированное @Id , просто представляет ключ документа и не обязательно является частью сохраненного документа JSON, если оно также не аннотировано @Field , как в следующем примере:

@Id
@Field
private String id;

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

@Field("fname")
private String firstName;

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

{
"firstName": "John",
"lastName": "Smith",
"created": 1457193705667
"_class": "com.foreach.spring.data.couchbase.model.Person"
}

Обратите внимание, что Spring Data автоматически добавляет в каждый документ атрибут, содержащий полное имя класса объекта. По умолчанию этот атрибут называется «_class» , хотя вы можете переопределить его в своем классе конфигурации Couchbase, переопределив метод typeKey() .

Например, если вы хотите назначить поле с именем «dataType» для хранения имен классов, вы должны добавить это в свой класс конфигурации Couchbase:

@Override
public String typeKey() {
return "dataType";
}

Еще одна популярная причина для переопределения typeKey() — если вы используете версию Couchbase Mobile, которая не поддерживает поля с префиксом подчеркивания. В этом случае вы можете выбрать свое собственное поле альтернативного типа, как в предыдущем примере, или вы можете использовать альтернативу, предоставленную Spring:

@Override
public String typeKey() {
// use "javaClass" instead of "_class"
return MappingCouchbaseConverter.TYPEKEY_SYNCGATEWAY_COMPATIBLE;
}

5. Репозиторий Couchbase

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

Мы объявляем интерфейс репозитория для класса Person , расширяя CrudRepository<String,Person> и добавляя производный метод запроса:

public interface PersonRepository extends CrudRepository<Person, String> {
List<Person> findByFirstName(String firstName);
}

6. Поддержка N1QL через индексы

При использовании Couchbase 4.0 или более поздней версии пользовательские запросы по умолчанию обрабатываются с использованием механизма N1QL (если только их соответствующие методы репозитория не снабжены аннотацией @View , чтобы указать на использование резервных представлений, как описано в следующем разделе).

Чтобы добавить поддержку N1QL, вы должны создать первичный индекс в корзине. Вы можете создать индекс, используя обработчик запросов командной строки cbq (см. документацию Couchbase о том, как запустить инструмент cbq для вашей среды) и введя следующую команду:

CREATE PRIMARY INDEX ON foreach USING GSI;

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

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

Вы также можете создать один или несколько вторичных индексов. Когда вы это сделаете, Couchbase будет использовать их по мере необходимости, чтобы оптимизировать обработку запросов.

Например, чтобы добавить индекс в поле firstName , введите следующую команду в инструменте cbq :

CREATE INDEX idx_firstName ON foreach(firstName) USING GSI;

7. Поддерживающие просмотры

Для каждого интерфейса репозитория вам потребуется создать проектный документ Couchbase и одно или несколько представлений в целевом сегменте. Имя проектного документа должно быть версией имени класса сущностей в нижнем верблюжьем регистре (например , «person» ).

Независимо от того, какую версию Couchbase Server вы используете, вы должны создать резервное представление с именем «все» , чтобы поддерживать встроенный метод репозитория « findAll» . Вот функция карты для представления «все» для нашего класса Person :

function (doc, meta) {
if(doc._class == "com.foreach.spring.data.couchbase.model.Person") {
emit(meta.id, null);
}
}

Каждый пользовательский метод репозитория должен иметь резервное представление при использовании версии Couchbase до 4.0 (использование резервных представлений необязательно в версии 4.0 или более поздней).

Пользовательские методы, поддерживаемые представлением, должны быть аннотированы с помощью @View , как в следующем примере:

@View
List<Person> findByFirstName(String firstName);

Соглашение об именах по умолчанию для резервных представлений заключается в использовании версии в нижнем верблюжьем регистре той части имени метода, которая следует за ключевым словом « find» (например , «byFirstName» ).

Вот как вы могли бы написать функцию карты для представления «byFirstName» :

function (doc, meta) {
if(doc._class == "com.foreach.spring.data.couchbase.model.Person"
&& doc.firstName) {
emit(doc.firstName, null);
}
}

Вы можете переопределить это соглашение об именах и использовать свои собственные имена представлений, указав в каждой аннотации @View имя соответствующего вспомогательного представления. Например:

@View("myCustomView")
List<Person> findByFirstName(String lastName);

8. Сервисный уровень

Для нашего сервисного уровня мы определяем интерфейс и две реализации: одну с использованием абстракции репозитория Spring Data, а другую с использованием абстракции шаблона Spring Data. Вот наш интерфейс PersonService :

public interface PersonService {
Person findOne(String id);
List<Person> findAll();
List<Person> findByFirstName(String firstName);

void create(Person person);
void update(Person person);
void delete(Person person);
}

8.1. Служба репозитория

Вот реализация с использованием репозитория, который мы определили выше:

@Service
@Qualifier("PersonRepositoryService")
public class PersonRepositoryService implements PersonService {

@Autowired
private PersonRepository repo;

public Person findOne(String id) {
return repo.findOne(id);
}

public List<Person> findAll() {
List<Person> people = new ArrayList<Person>();
Iterator<Person> it = repo.findAll().iterator();
while(it.hasNext()) {
people.add(it.next());
}
return people;
}

public List<Person> findByFirstName(String firstName) {
return repo.findByFirstName(firstName);
}

public void create(Person person) {
person.setCreated(DateTime.now());
repo.save(person);
}

public void update(Person person) {
person.setUpdated(DateTime.now());
repo.save(person);
}

public void delete(Person person) {
repo.delete(person);
}
}

8.2. Служба шаблонов

Для реализации на основе шаблона мы должны создать вспомогательные представления, перечисленные в разделе 7 выше. Объект CouchbaseTemplate доступен в нашем контексте Spring и может быть внедрен в класс обслуживания.

Вот реализация с использованием абстракции шаблона:

@Service
@Qualifier("PersonTemplateService")
public class PersonTemplateService implements PersonService {
private static final String DESIGN_DOC = "person";
@Autowired
private CouchbaseTemplate template;

public Person findOne(String id) {
return template.findById(id, Person.class);
}

public List<Person> findAll() {
return template.findByView(ViewQuery.from(DESIGN_DOC, "all"), Person.class);
}

public List<Person> findByFirstName(String firstName) {
return template.findByView(ViewQuery.from(DESIGN_DOC, "byFirstName"), Person.class);
}

public void create(Person person) {
person.setCreated(DateTime.now());
template.insert(person);
}

public void update(Person person) {
person.setUpdated(DateTime.now());
template.update(person);
}

public void delete(Person person) {
template.remove(person);
}
}

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

Мы показали, как настроить проект для использования модуля Spring Data Couchbase и как написать простой класс сущности и интерфейс его репозитория. Мы написали простой интерфейс службы и предоставили одну реализацию с использованием репозитория и другую реализацию с использованием API шаблона Spring Data.

Вы можете просмотреть полный исходный код этого руководства в проекте GitHub .

Для получения дополнительной информации посетите сайт проекта Spring Data Couchbase .