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

Проверка сущностей, оптимистическая блокировка и согласованность запросов в Spring Data Couchbase

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

1. Введение

После знакомства с Spring Data Couchbase в этом втором руководстве мы сосредоточимся на поддержке проверки объектов (JSR-303), оптимистической блокировки и различных уровнях согласованности запросов для базы данных документов Couchbase.

2. Проверка сущности

Spring Data Couchbase обеспечивает поддержку аннотаций проверки объектов JSR-303. Чтобы воспользоваться этой функцией, сначала мы добавим библиотеку JSR-303 в раздел зависимостей нашего проекта Maven:

<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
<version>1.1.0.Final</version>
</dependency>

Затем мы добавляем реализацию JSR-303. Мы будем использовать реализацию Hibernate:

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

Наконец, мы добавляем фабричный компонент валидатора и соответствующий прослушиватель событий Couchbase в нашу конфигурацию Couchbase:

@Bean
public LocalValidatorFactoryBean localValidatorFactoryBean() {
return new LocalValidatorFactoryBean();
}

@Bean
public ValidatingCouchbaseEventListener validatingCouchbaseEventListener() {
return new ValidatingCouchbaseEventListener(localValidatorFactoryBean());
}

Эквивалентная конфигурация XML выглядит следующим образом:

<bean id="validator"
class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean"/>

<bean id="validatingEventListener"
class="org.springframework.data.couchbase.core.mapping.event.ValidatingCouchbaseEventListener"/>

Теперь мы добавляем аннотации JSR-303 к нашим классам сущностей. Когда нарушение ограничения встречается во время операции сохраняемости, операция завершится ошибкой, выбрасывая ConstraintViolationException .

Вот пример ограничений, которые мы можем применить к нашим сущностям Student :

@Field
@NotNull
@Size(min=1, max=20)
@Pattern(regexp="^[a-zA-Z .'-]+$")
private String firstName;

...
@Field
@Past
private DateTime dateOfBirth;

3. Оптимистичная блокировка

Spring Data Couchbase не поддерживает транзакции с несколькими документами, подобные тем, которые вы можете реализовать в других модулях Spring Data, таких как Spring Data JPA (через аннотацию @Transactional ), а также не предоставляет функцию отката.

Однако он поддерживает оптимистическую блокировку почти так же, как и другие модули Spring Data, за счет использования аннотации @Version :

@Version
private long version;

Под прикрытием Couchbase использует так называемый механизм «сравнения и замены» (CAS) для достижения оптимистичной блокировки на уровне хранилища данных.

Каждый документ в Couchbase имеет связанное значение CAS, которое автоматически изменяется каждый раз, когда изменяются метаданные или содержимое документа. Использование аннотации @Version в поле приводит к тому, что это поле заполняется текущим значением CAS всякий раз, когда документ извлекается из Couchbase.

Когда вы пытаетесь сохранить документ обратно в Couchbase, это поле проверяется на соответствие текущему значению CAS в Couchbase. Если значения не совпадают, операция сохранения завершится с ошибкой OptimisticLockingException .

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

4. Согласованность запросов

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

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

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

4.1. Уровни согласованности

Spring Data позволяет указать различные уровни согласованности и устаревания запросов для вашего приложения с помощью перечисления Consistency , которое находится в пакете org.springframework.data.couchbase.core.query .

Это перечисление определяет следующие уровни согласованности и устаревания запросов, от наименее до наиболее строгого:

  • EVENTUALLY_CONSISTENT

  • устаревшие чтения разрешены

  • индексы обновляются по стандартному алгоритму Couchbase

  • ОБНОВЛЕНИЕ_ПОСЛЕ

  • устаревшие чтения разрешены

  • индексы обновляются после каждого запроса

  • DEFAULT_CONSISTENCY (аналогично READ_YOUR_OWN_WRITES )

  • READ_YOUR_OWN_WRITES

  • устаревшие чтения не допускаются

  • индексы обновляются после каждого запроса

  • СИЛЬНО_ПОСЛЕДОВАТЕЛЬНО

  • устаревшие чтения не допускаются

  • индексы обновляются после каждого оператора

4.2. Поведение по умолчанию

Рассмотрим случай, когда у вас есть документы, которые были удалены из Couchbase, а резервные представления и индексы не были полностью обновлены.

Встроенный метод CouchbaseRepository deleteAll () безопасно игнорирует документы, которые были найдены вспомогательным представлением, но удаление которых еще не отражено представлением.

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

Для всех других методов шаблонов, встроенных методов репозитория и производных методов запросов к репозиторию, согласно официальной документации Spring Data Couchbase 2.1.x на момент написания этой статьи, Spring Data использует уровень согласованности по умолчанию Consistency.READ_YOUR_OWN_WRITES.

Стоит отметить, что в более ранних версиях библиотеки по умолчанию использовалось Consistency.UPDATE_AFTER .

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

4.3. Глобальная настройка согласованности

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

Вот как вы можете переопределить глобальный уровень согласованности в своем классе конфигурации Couchbase:

@Override
public Consistency getDefaultConsistency() {
return Consistency.STRONGLY_CONSISTENT;
}

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

<couchbase:template consistency="STRONGLY_CONSISTENT"/>

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

Например, хранилище данных или приложение для создания отчетов, в котором данные часто добавляются или обновляются только в пакетном режиме, были бы хорошим кандидатом на EVENTUALLY_CONSISTENT , тогда как приложение OLTP, вероятно, должно стремиться к более строгим уровням, таким как READ_YOUR_OWN_WRITES или STRONGLY_CONSISTENT .

4.4. Пользовательская реализация согласованности

Если вам нужны более точные настройки согласованности, вы можете переопределить уровень согласованности по умолчанию для каждого запроса, предоставив собственную реализацию репозитория для любых запросов, уровень согласованности которых вы хотите контролировать независимо, и используя queryView и/или методы queryN1QL , предоставляемые CouchbaseTemplate .

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

Сначала создайте интерфейс, содержащий объявление пользовательского метода:

public interface CustomStudentRepository {
List<Student> findByFirstNameStartsWith(String s);
}

Затем реализуйте интерфейс, установив параметр Stale из базового Couchbase Java SDK на желаемый уровень:

public class CustomStudentRepositoryImpl implements CustomStudentRepository {

@Autowired
private CouchbaseTemplate template;

public List<Student> findByFirstNameStartsWith(String s) {
return template.findByView(ViewQuery.from("student", "byFirstName")
.startKey(s)
.stale(Stale.FALSE),
Student.class);
}
}

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

public interface StudentRepository extends CrudRepository<Student, String>,
CustomStudentRepository {
...
}

5. Вывод

В этом руководстве мы показали, как реализовать проверку объекта JSR-303 и добиться возможности оптимистической блокировки при использовании проекта сообщества Spring Data Couchbase.

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

Наконец, мы объяснили уровни согласованности по умолчанию, используемые Spring Data Couchbase в глобальном масштабе и для нескольких конкретных методов, и продемонстрировали способы переопределения глобальных настроек согласованности по умолчанию, а также способы переопределения настроек согласованности для каждого запроса путем предоставления ваши собственные реализации пользовательских репозиториев.

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

Чтобы узнать больше о Spring Data Couchbase, посетите официальный сайт проекта Spring Data Couchbase .