© 2008-2022 The original authors.
Copies of this document may be made for your own use and for distribution to others, provided that you do not charge any fee for such copies and further provided that each copy contains this Copyright Notice, whether distributed in print or electronically. |
Preface
1. Project Metadata
-
Version control: https://github.com/spring-projects/spring-data-keyvalue
-
Bugtracker: https://github.com/spring-projects/spring-data-keyvalue/issues
-
Release repository: https://repo1.maven.org/maven2/
-
Milestone repository: https://repo.spring.io/milestone
-
Snapshot repository: https://repo.spring.io/snapshot
Unresolved directive in index.adoc - include::https://raw.githubusercontent.com/spring-projects/spring-data-commons/master/src/main/asciidoc/repositories.adoc[leveloffset=+1]
Reference Documentation
2. Key-Value Repositories
This chapter explains concepts and usage patterns you need to know when working with the key-value abstraction and the java.util.Map
based implementation provided by Spring Data Key Value.
2.1. Core Concepts
The key-value abstraction within Spring Data Key Value requires an Adapter
that shields the native store implementation, freeing up KeyValueTemplate
to work on top of any key-value pair-like structure. Keys are distributed across Keyspaces. Unless otherwise specified, the class name is used as the default keyspace for an entity. The following interface definition shows the KeyValueOperations
interface, which is the heart of Spring Data Key-Value:
interface KeyValueOperations {
<T> T insert(T objectToInsert); (1)
void update(Object objectToUpdate); (2)
void delete(Class<?> type); (3)
<T> T findById(Object id, Class<T> type); (4)
<T> Iterable<T> findAllOf(Class<T> type); (5)
<T> Iterable<T> find(KeyValueQuery<?> query, Class<T> type); (6)
//... more functionality omitted.
}
1 | Inserts the given entity and assigns an ID (if required). |
2 | Updates the given entity. |
3 | Removes all entities of the matching type. |
4 | Returns the entity of the given type with its matching ID. |
5 | Returns all entities of the matching type. |
6 | Returns a List of all entities of the given type that match the criteria of the query. |
2.2. Configuring The KeyValueTemplate
In its very basic shape, the KeyValueTemplate
uses a MapAdapter
that wraps a ConcurrentHashMap
and that uses Spring Expression Language to run queries and sorting.
The used KeyValueAdapter does the heavy lifting when it comes to storing and retrieving data. The data structure influences performance and multi-threading behavior.
|
You can use a different type or pre-initialize the adapter with some values, and you can do so by using various constructors on MapKeyValueAdapter
, as the following example shows:
@EnableMapRepositories
@Configuration
class MyConfiguration {
@Bean
public KeyValueOperations mapKeyValueTemplate() { (1)
return new KeyValueTemplate(keyValueAdapter());
}
@Bean
public KeyValueAdapter keyValueAdapter() {
return new MapKeyValueAdapter(ConcurrentHashMap.class); (2)
}
}
1 | Defines a custom KeyValueOperations bean using the default bean name. See documentation and properties of @EnableMapRepositories for further customization. |
2 | Defines a custom KeyValueAdapter bean using a ConcurrentHashMap as storage that is used by KeyValueTemplate . |
2.3. Keyspaces
Keyspaces define the part of the data structure in which the entity should be kept.This concept is similar to collections in MongoDB and Elasticsearch, cores in Solr, and tables in JPA.
By default, the keyspace of an entity is extracted from its type, but you can also store entities of different types within one keyspace.In that case, any find operation type-checks the results.The following example shows a keyspace for a repository of Person
objects:
@KeySpace("persons")
class Person {
@Id String id;
String firstname;
String lastname;
}
class User extends Person {
String username;
}
template.findAllOf(Person.class); (1)
template.findAllOf(User.class); (2)
1 | Returns all entities for the persons keyspace. |
2 | Returns only elements of type User stored in persons keyspace. |
@KeySpace supports SpEL expressions allowing dynamic keyspace configuration.
|
5.2.0.M3
2.3.1. Custom KeySpace Annotation
You can compose your own KeySpace
annotations for a more domain-centric usage by annotating one of the attributes with @AliasFor
.
The composed annotation must inherit @Persistent .
|
The following example shows a custom @KeySpace
annotation:
@KeySpace
@Persistent
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.TYPE })
static @interface CacheCentricAnnotation {
@AliasFor(annotation = KeySpace.class, attribute = "value")
String cacheRegion() default "";
}
@CacheCentricAnnotation(cacheRegion = "customers")
class Customer {
//...
}
2.4. Querying
Running queries is managed by a QueryEngine
.
As mentioned earlier, you can instruct the KeyValueAdapter
to use an implementation-specific QueryEngine
that allows access to native functionality.
When used without further customization, queries can be run by using SpELQueryEngine
.
For performance reasons, we highly recommend to have at least Spring Framework 4.1.2 or better to make use of compiled SpEL Expressions.
(“SpEL” is short for “Spring Expression Language”.) You can use the -Dspring.expression.compiler.mode=IMMEDIATE switch to enable it.
|
The following example shows a query that uses the SpEL:
KeyValueQuery<String> query = new KeyValueQuery<String>("lastname == 'targaryen'");
List<Person> targaryens = template.find(query, Person.class);
You must have getters and setters present to query properties when you use SpEL. |
2.5. Sorting
Depending on the store implementation provided by the adapter, entities might already be stored in some sorted way but do not necessarily have to be.Again, the underlying QueryEngine
is capable of performing sort operations.
When used without further customization, sorting is done by using a SpelPropertyComparator
extracted from the Sort
clause.The following example shows a query with a Sort
clause:
KeyValueQuery<String> query = new KeyValueQuery<String>("lastname == 'baratheon'");
query.setSort(Sort.by(DESC, "age"));
List<Person> targaryens = template.find(query, Person.class);
Please note that you need to have getters and setters present to sort using SpEL. |
2.6. Map Repositories
Map repositories reside on top of the KeyValueTemplate
. Using the default SpelQueryCreator
allows deriving query and sort expressions from the given method name, as the following example shows:
@Configuration
@EnableMapRepositories
class KeyValueConfig {
}
interface PersonRepository implements CrudRepository<Person, String> {
List<Person> findByLastname(String lastname);
}