1. Introduction

The Spring Data Key Value framework makes it easy to write Spring applications that use key-value stores.

It minimizes redundant tasks and boilerplate code required for interacting with the store. The framework works well for key-value stores like Redis and Riak.

In this tutorial, we’ll cover how we can use Spring Data Key Value with the default java.util.Map based implementation.

2. Requirements

The Spring Data Key Value 1.x binaries require JDK level 6.0 or above, and Spring Framework 3.0.x or above.

3. Maven Dependency

To work with Spring Data Key Value, we need to add the following dependency:

<dependency>
    <groupId>org.springframework.data</groupId>
    <artifactId>spring-data-keyvalue</artifactId>
    <version>2.0.6.RELEASE</version>
</dependency>

The latest version can be found here.

4. Creating an Entity

Let’s create an Employee entity:

@KeySpace("employees")
public class Employee {

    @Id
    private Integer id;

    private String name;

    private String department;

    private String salary;

    // constructors/ standard getters and setters

}

Keyspaces define in which part of the data structure the entity should be kept. This concept is very 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.

5. Repository

Similar to other Spring Data frameworks, we will need to activate Spring Data repositories using the @EnableMapRepositories annotation.

By default, the repositories will use the *ConcurrentHashMap-*based implementation:

@SpringBootApplication
@EnableMapRepositories
public class SpringDataKeyValueApplication {
}

It’s possible to change the default ConcurrentHashMap implementation and use some other java.util.Map implementations:

@EnableMapRepositories(mapType = WeakHashMap.class)

Creating repositories with Spring Data Key Value works the same way as with other Spring Data frameworks:

@Repository
public interface EmployeeRepository
  extends CrudRepository<Employee, Integer> {
}

For learning more about Spring Data repositories we can have a look at this article.

6. Using the Repository

By extending CrudRepository in EmployeeRepository, we get a complete set of persistence methods that perform CRUD functionality.

Now, we’ll see how we can use some of the available persistence methods.

6.1. Saving an Object

Let’s save a new Employee object to the data store using the repository:

Employee employee = new Employee(1, "Mike", "IT", "5000");
employeeRepository.save(employee);

6.2. Retrieving an Existing Object

We can verify the correct save of the employee in the previous section by fetching the employee:

Optional<Employee> savedEmployee = employeeRepository.findById(1);

6.3. Updating an Existing Object

CrudRepository doesn’t provide a dedicated method for updating an object.

Instead, we can use the save() method:

employee.setName("Jack");
employeeRepository.save(employee);

6.4. Deleting an Existing Object

We can delete the inserted object using the repository:

employeeRepository.deleteById(1);

6.5. Fetch All Objects

We can fetch all the saved objects:

Iterable<Employee> employees = employeeRepository.findAll();

7. KeyValueTemplate

Another way of performing operations on the data structure is by using KeyValueTemplate.

In very basic terms, the KeyValueTemplate uses a MapAdapter wrapping a java.util.Map implementation to perform queries and sorting:

@Bean
public KeyValueOperations keyValueTemplate() {
    return new KeyValueTemplate(keyValueAdapter());
}

@Bean
public KeyValueAdapter keyValueAdapter() {
    return new MapKeyValueAdapter(WeakHashMap.class);
}

Note that in case we have used @EnableMapRepositories, we don’t need to specify a KeyValueTemplate. It will be created by the framework itself.

8. Using KeyValueTemplate

Using KeyValueTemplate, we can perform the same operations as we did with the repository.

8.1. Saving an Object

Let’s see how to save a new Employee object to the data store using a template:

Employee employee = new Employee(1, "Mile", "IT", "5000");
keyValueTemplate.insert(employee);

8.2. Retrieving an Existing Object

We can verify the insertion of the object by fetching it from the structure using template:

Optional<Employee> savedEmployee = keyValueTemplate
  .findById(id, Employee.class);

8.3. Updating an Existing Object

Unlike CrudRepository, the template provides a dedicated method to update an object:

employee.setName("Jacek");
keyValueTemplate.update(employee);

8.4. Deleting an Existing Object

We can delete an object with a template:

keyValueTemplate.delete(id, Employee.class);

8.5. Fetch All Objects

We can fetch all the saved objects using a template:

Iterable<Employee> employees = keyValueTemplate
  .findAll(Employee.class);

8.6. Sorting the Objects

In addition to the basic functionality, the template also supports KeyValueQuery for writing custom queries.

For example, we can use a query to get a sorted list of Employees based on their salary:

KeyValueQuery<Employee> query = new KeyValueQuery<Employee>();
query.setSort(new Sort(Sort.Direction.DESC, "salary"));
Iterable<Employee> employees 
  = keyValueTemplate.find(query, Employee.class);

9. Conclusion

This article showcased how we can use Spring Data KeyValue framework with the default Map implementation using Repository or KeyValueTemplate.

There are more Spring Data Frameworks like Spring Data Redis which are written on top of Spring Data Key Value. Refer to this article for an introduction to Spring Data Redis.

And, as always, all code samples shown here are available over on GitHub.