DATACOUCH-148 - Allow to configure repository queries consistency globally.

The consistency to apply on generated view queries (Stale) and N1QL queries (ScanConsistency) can now be chosen via the configuration, through a more abstract Consistency enumeration.

It is accessed from the CouchbaseOperations interface but is used in the repository only. In xml, the consistency attribute is on the couchbase:template element (string value of the enum to be passed in).

Documentation has been amended to describe this feature.
This commit is contained in:
Simon Baslé
2015-07-27 17:17:21 +02:00
parent 508f190270
commit f543e2b037
15 changed files with 343 additions and 100 deletions

View File

@@ -27,6 +27,8 @@ import com.couchbase.client.java.CouchbaseCluster;
import com.couchbase.client.java.cluster.ClusterInfo;
import com.couchbase.client.java.env.CouchbaseEnvironment;
import com.couchbase.client.java.env.DefaultCouchbaseEnvironment;
import com.couchbase.client.java.query.Query;
import com.couchbase.client.java.view.ViewQuery;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.annotation.Bean;
@@ -41,6 +43,7 @@ import org.springframework.data.couchbase.core.convert.translation.JacksonTransl
import org.springframework.data.couchbase.core.convert.translation.TranslationService;
import org.springframework.data.couchbase.core.mapping.CouchbaseMappingContext;
import org.springframework.data.couchbase.core.mapping.Document;
import org.springframework.data.couchbase.core.view.Consistency;
import org.springframework.data.mapping.model.CamelCaseAbbreviatingFieldNamingStrategy;
import org.springframework.data.mapping.model.FieldNamingStrategy;
import org.springframework.data.mapping.model.PropertyNameFieldNamingStrategy;
@@ -136,11 +139,16 @@ public abstract class AbstractCouchbaseConfiguration {
/**
* Creates a {@link CouchbaseTemplate}.
*
* This uses {@link #couchbaseClusterInfo()}, {@link #couchbaseClient()}, {@link #mappingCouchbaseConverter()},
* , {@link #translationService()} and {@link #getDefaultConsistency()} for construction.
*
* @throws Exception on Bean construction failure.
*/
@Bean(name = BeanNames.COUCHBASE_TEMPLATE)
public CouchbaseTemplate couchbaseTemplate() throws Exception {
return new CouchbaseTemplate(couchbaseClusterInfo(), couchbaseClient(), mappingCouchbaseConverter(), translationService());
CouchbaseTemplate template = new CouchbaseTemplate(couchbaseClusterInfo(), couchbaseClient(), mappingCouchbaseConverter(), translationService());
template.setDefaultConsistency(getDefaultConsistency());
return template;
}
/**
@@ -257,4 +265,14 @@ public abstract class AbstractCouchbaseConfiguration {
protected FieldNamingStrategy fieldNamingStrategy() {
return abbreviateFieldNames() ? new CamelCaseAbbreviatingFieldNamingStrategy() : PropertyNameFieldNamingStrategy.INSTANCE;
}
}
/**
* Configures the default consistency for generated {@link ViewQuery view queries}
* and {@link Query N1QL queries} in repositories.
*
* @return the {@link Consistency consistency} to apply by default on generated queries.
*/
protected Consistency getDefaultConsistency() {
return Consistency.DEFAULT_CONSISTENCY;
}
}

View File

@@ -16,6 +16,8 @@
package org.springframework.data.couchbase.config;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Element;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
@@ -23,6 +25,7 @@ import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.data.couchbase.core.CouchbaseTemplate;
import org.springframework.data.couchbase.core.view.Consistency;
import org.springframework.util.StringUtils;
/**
@@ -34,6 +37,8 @@ import org.springframework.util.StringUtils;
*/
public class CouchbaseTemplateParser extends AbstractSingleBeanDefinitionParser {
private static final Logger LOGGER = LoggerFactory.getLogger(CouchbaseTemplateParser.class);
/**
* Resolve the bean ID and assign a default if not set.
*
@@ -82,6 +87,17 @@ public class CouchbaseTemplateParser extends AbstractSingleBeanDefinitionParser
if (StringUtils.hasText(translationServiceRef)) {
bean.addConstructorArgReference(translationServiceRef);
}
String consistencyValue = element.getAttribute("consistency");
if (consistencyValue != null) {
try {
Consistency consistency = Consistency.valueOf(consistencyValue);
bean.addPropertyValue("defaultConsistency", consistency);
} catch (IllegalArgumentException e) {
//bad consistency, leave default and log
LOGGER.warn("Parsed bad consistency value " + consistencyValue + " in xml template configuration, using default");
}
}
}
}

View File

@@ -33,6 +33,7 @@ import com.couchbase.client.java.view.ViewResult;
import org.springframework.data.couchbase.core.convert.CouchbaseConverter;
import org.springframework.data.couchbase.core.convert.translation.TranslationService;
import org.springframework.data.couchbase.core.view.Consistency;
/**
* Defines common operations on the Couchbase data source, most commonly implemented by {@link CouchbaseTemplate}.
@@ -341,4 +342,12 @@ public interface CouchbaseOperations {
*/
CouchbaseConverter getConverter();
/**
* Returns the {@link Consistency consistency} parameter to be used by default for generated queries (views and N1QL)
* in repositories. Defaults to {@link Consistency#DEFAULT_CONSISTENCY}.
*
* @return the consistency to use for generated repository queries.
*/
Consistency getDefaultConsistency();
}

View File

@@ -36,8 +36,10 @@ import com.couchbase.client.java.document.json.JsonObject;
import com.couchbase.client.java.error.CASMismatchException;
import com.couchbase.client.java.error.TranscodingException;
import com.couchbase.client.java.query.Query;
import com.couchbase.client.java.query.QueryParams;
import com.couchbase.client.java.query.QueryResult;
import com.couchbase.client.java.query.QueryRow;
import com.couchbase.client.java.query.consistency.ScanConsistency;
import com.couchbase.client.java.util.features.CouchbaseFeature;
import com.couchbase.client.java.view.ViewQuery;
import com.couchbase.client.java.view.ViewResult;
@@ -65,6 +67,7 @@ import org.springframework.data.couchbase.core.mapping.event.BeforeConvertEvent;
import org.springframework.data.couchbase.core.mapping.event.BeforeDeleteEvent;
import org.springframework.data.couchbase.core.mapping.event.BeforeSaveEvent;
import org.springframework.data.couchbase.core.mapping.event.CouchbaseMappingEvent;
import org.springframework.data.couchbase.core.view.Consistency;
import org.springframework.data.mapping.PersistentPropertyAccessor;
import org.springframework.data.mapping.context.MappingContext;
import org.springframework.data.mapping.model.ConvertingPropertyAccessor;
@@ -100,6 +103,9 @@ public class CouchbaseTemplate implements CouchbaseOperations, ApplicationEventP
protected final MappingContext<? extends CouchbasePersistentEntity<?>, CouchbasePersistentProperty> mappingContext;
//default value is in case the template isn't constructed through configuration mechanisms that use the setter.
private Consistency configuredConsistency = Consistency.DEFAULT_CONSISTENCY;
public CouchbaseTemplate(final ClusterInfo clusterInfo, final Bucket client) {
this(clusterInfo, client, null, null);
}
@@ -576,4 +582,13 @@ public class CouchbaseTemplate implements CouchbaseOperations, ApplicationEventP
public CouchbaseConverter getConverter() {
return this.converter;
}
@Override
public Consistency getDefaultConsistency() {
return configuredConsistency;
}
public void setDefaultConsistency(Consistency consistency) {
this.configuredConsistency = consistency;
}
}

View File

@@ -0,0 +1,72 @@
/*
* Copyright 2012-2015 the original author or authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.couchbase.core.view;
import com.couchbase.client.java.query.consistency.ScanConsistency;
import com.couchbase.client.java.view.Stale;
/**
* Enumeration of different consistency configurations to be used by the queries generated by the
* framework.
*
* Each consistency can be translated to a {@link Stale} (for the {@link #viewConsistency() views})
* and {@link ScanConsistency} (for the {@link #n1qlConsistency() N1QL queries}).
*
* @author Simon Baslé
*/
public enum Consistency {
/** READ_YOUR_OWN_WRITES is {@link Stale#FALSE} and {@link ScanConsistency#STATEMENT_PLUS} */
READ_YOUR_OWN_WRITES(Stale.FALSE, ScanConsistency.STATEMENT_PLUS),
/** STRONGLY_CONSISTENT is {@link Stale#FALSE} and {@link ScanConsistency#REQUEST_PLUS} */
STRONGLY_CONSISTENT(Stale.FALSE, ScanConsistency.REQUEST_PLUS),
/** UPDATE_AFTER is {@link Stale#UPDATE_AFTER} and {@link ScanConsistency#NOT_BOUNDED} */
UPDATE_AFTER(Stale.UPDATE_AFTER, ScanConsistency.NOT_BOUNDED),
/** EVENTUALLY_CONSISTENT is {@link Stale#TRUE} and {@link ScanConsistency#NOT_BOUNDED} */
EVENTUALLY_CONSISTENT(Stale.TRUE, ScanConsistency.NOT_BOUNDED);
/**
* The static default Consistency ({@link #UPDATE_AFTER}).
*/
public static final Consistency DEFAULT_CONSISTENCY = UPDATE_AFTER;
private final Stale viewConsistency;
private final ScanConsistency n1qlConsistency;
Consistency(Stale viewConsistency, ScanConsistency n1qlConsistency) {
this.viewConsistency = viewConsistency;
this.n1qlConsistency = n1qlConsistency;
}
/**
* Returns the {@link Stale view consistency} corresponding to this {@link Consistency}.
*
* @return the view consistency.
*/
public Stale viewConsistency() {
return viewConsistency;
}
/**
* Returns the {@link ScanConsistency N1QL consistency} corresponding to this {@link Consistency}.
*
* @return the N1QL consistency.
*/
public ScanConsistency n1qlConsistency() {
return n1qlConsistency;
}
}

View File

@@ -20,7 +20,9 @@ import java.util.List;
import com.couchbase.client.java.document.json.JsonArray;
import com.couchbase.client.java.query.Query;
import com.couchbase.client.java.query.QueryParams;
import com.couchbase.client.java.query.Statement;
import com.couchbase.client.java.query.consistency.ScanConsistency;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -57,18 +59,20 @@ public abstract class AbstractN1qlBasedQuery implements RepositoryQuery {
Statement statement = getStatement(accessor);
JsonArray queryPlaceholderValues = getPlaceholderValues(accessor);
Query query = buildQuery(statement, queryPlaceholderValues);
Query query = buildQuery(statement, queryPlaceholderValues,
getCouchbaseOperations().getDefaultConsistency().n1qlConsistency());
return executeDependingOnType(query, queryMethod, queryMethod.isPageQuery(), queryMethod.isModifyingQuery(),
queryMethod.isSliceQuery());
}
protected static Query buildQuery(Statement statement, JsonArray queryPlaceholderValues) {
protected static Query buildQuery(Statement statement, JsonArray queryPlaceholderValues, ScanConsistency scanConsistency) {
QueryParams queryParams = QueryParams.build().consistency(scanConsistency);
Query query;
if (!queryPlaceholderValues.isEmpty()) {
query = Query.parameterized(statement, queryPlaceholderValues);
query = Query.parameterized(statement, queryPlaceholderValues, queryParams);
}
else {
query = Query.simple(statement);
query = Query.simple(statement, queryParams);
}
if (LOG.isDebugEnabled()) {

View File

@@ -68,7 +68,8 @@ public class ViewBasedCouchbaseQuery implements RepositoryQuery {
boolean isReduce = methodName.startsWith("count");
String viewName = StringUtils.uncapitalize(methodName.replaceFirst("find|count", ""));
ViewQuery simpleQuery = ViewQuery.from(designDoc, viewName);
ViewQuery simpleQuery = ViewQuery.from(designDoc, viewName)
.stale(operations.getDefaultConsistency().viewConsistency());
if (isReduce) {
simpleQuery.reduce(isReduce);
return executeReduce(simpleQuery, designDoc, viewName);
@@ -80,7 +81,8 @@ public class ViewBasedCouchbaseQuery implements RepositoryQuery {
protected Object deriveAndExecute(Object[] runtimeParams) {
String designDoc = designDocName(method);
String viewName = method.getViewAnnotation().viewName();
ViewQuery baseQuery = ViewQuery.from(designDoc, viewName);
ViewQuery baseQuery = ViewQuery.from(designDoc, viewName)
.stale(operations.getDefaultConsistency().viewConsistency());
try {
PartTree tree = new PartTree(method.getName(), method.getEntityInformation().getJavaType());