2

While trying to understand the purpose of 'Spring Data' i came across this article and tried few examples with Gemfire/ Redis repositories and their corresponding Spring-Data components. Could someone help me with the following questions.

Scenario: When GemFire was my datastore, i had to use methods create, get and remove on the GemFireTemplate to perform the CRUD operations. When Redis was my datastore, I had to use methods .opsForHash().put , .opsForHash().get and .opsForHash().delete on the RedisTemplate to perform the same CRUD operations.

Question:

Isn't Spring-Data supposed to provide a level of abstraction to the underlying data store ? If i am expected to know the respective CRUD methods and have different APIs based on the underlying data store, what kind of abstraction does Spring-Data components bring in ? Can't I directly use a Jedis or Java client for Gemfire to perform these datatstore specific CRUD operations ?

This link seems to explain that but, looks like i need some help in understanding it.

there is no general API to all the persistence stores. The differences are too fundamental. But the Spring Data project does provide a common programming model to access your data

yathirigan
  • 5,619
  • 22
  • 66
  • 104

3 Answers3

6

Thanks for your question, as Master Slave has already pointed out nicely the benefits that Spring Data provides are manifold but there are sometimes functional differences in the sense of supported features between store modules. Those are partly motivated by the different characteristics and capabilities of the particular underlying datastore as well as focus and time constraints.

Redis and Gemfire are to some extend similar store technologies by providing a key-value like storage and access model. However Gemfire provides much richer query capabilities than Redis does. Thats one of the reasons why Spring Data Gemfire already has a Repository abstraction for quite a while.

Redis on the other hand is a different story - as Master Slave already mentioned, you can easily build your own customised Redis Repository - and that is what many people do - but usually the interactions with Redis are quite unique to the use case so we didn't see that much functional overlap to motivate a generic implementation that does more than just "save" and "load".

We have a ticket for adding a Repository abstraction to Spring Data Redis but we haven't had the time to do it yet.

Thomas Darimont
  • 1,356
  • 11
  • 14
  • thanks for the additional details and also for pointing to the Gemfire repository abstraction. I will look into it. – yathirigan Mar 16 '15 at 18:25
3

Spring data does provide a level of abstraction to the underlying data store. However, NoSQL stores are a very diverse spectrum, one is a graph database, the other is specialized for storing documents, the third for storing key-value pairs etc. Nonetheless, these are not the differences that you want to abstract away, these are the unique feature that made you choose them in the first place.

On the other hand, Spring Data gives you consistency and means to apply the known patterns against these different store

  • It gives you a consisent way to configure resources for accessing the stores
  • Mapping and conversion between the underlying types and Java types
  • A repository abstraction for most of the stores that boils down to only declaring the interface for the basic CRUD operation. The implementation and the store-specific stuff is handled by Spring Data
  • Dedicate Template implementation that provide callbacks for accessing native APIs

The list goes on. The point is that Spring Data does provide a level of abstraction as much as it is possible, but it also doesn't restrict the exposed functionality to a least known common denominator as that would take away the benefits of the different stores.

Master Slave
  • 27,771
  • 4
  • 57
  • 55
  • Q1. >> these are not the differences that you want to abstract away << - Wouldn't they have abstraction at-least among common type of data stores. for e.g. Both Redis and Gemfire are Key-Value stores but, looks like there isn't CRUDRepositories for these, instead i have to use templates to directly access their respective native APIs only, defeating the purpose of going to Spring-data of these repositories. – yathirigan Mar 10 '15 at 13:49
  • I believe CRUDRepositories serve this purpose, is that correct ? – yathirigan Mar 10 '15 at 13:55
  • 2
    exactly, CRUDRespository is the common abstarction layer, and based on it you would get a consistent CRUD operation interface for both GemFire and Redis – Master Slave Mar 10 '15 at 13:58
  • >> consistent way to configure resources << and >> Mapping and conversion << if you don't mind , could you please throw some more light on this or any article explaining this. I am searching for an article that has an comparison on what code/config i would have to write if there was no spring-data and how code/configuration is simplified by using spring-data .. – yathirigan Mar 10 '15 at 13:59
  • See this article for GemFire implementation https://spring.io/guides/gs/accessing-data-gemfire/, thanks to Spring Data you can achieve the same with Redis store with minimal code rewrites – Master Slave Mar 10 '15 at 14:00
3

Some additional thoughts on the subject...

One of the many advantages in using Spring Templates for data store-specific access (e.g. GemfireTemplate) is that they shield developers from underlying data store API changes around which the Templates typically wrap. If the data store vendor makes API interface breaking changes (which has been the case for GemFire) then the Template can provide a layer of abstraction/adaption to the underlying API without changes to the user application.

In addition, the Template can leverage other Spring Infrastructure Management like Transactions that would typically not be inherently built into the underly data store APIs itself. Templates can also provide a facade and layer of convenience for several distinct APIs in the underlying data store product.

For instance, GemfireTemplate encapsulates operations to 'get' and 'put' data along with 'querying' the data of interest.

To do the former in GemFire, you would need to do the following...

Region<String, SomeValue> example = gemfireCache.getRegion("/Example");

example.put("someKey", new SomeValue(..));
...
SomeValue someValue = example.get("someKey");

While to query the data in '/Example', you would...

Region<String, SomeValue> example = gemfireCache.getRegion("/Example");
QueryService queryService = example.getQueryService();
Query query = queryService.newQuery("SELECT * FROM /Example WHERE ...");
Object result = query.execute(<any args for query parameters>);

if (result instanceof SelectResults) {
  SelectResults<SomeValue> someValues = (SelectResults) result;
  // process the query results
}
else {
  // figure out what happened
}

Now, contrast that with the Spring Template to get/put data

gemfireTemplate.put("someKey", new SomeValue(..));
...
SomeValue someValule = gemfireTemplate.get("someKey");

And querying...

SelectResults<SomeValue> results = gemfireTemplate.find("SELECT * FROM /Example WHERE ...", args);

// process the query results

If an Exception happens, or the results could not be collected, then GemFires' Exceptions/Errors are uniformly mapped to the core Spring Framework DAO Exception hierarchy, yet another advantage, which makes switching underly data stores easier, along with the consistent transaction handling.

Finally, while both Thomas Darimont and Master Slave nicely summed up the advantages of the using the Spring Data Repository abstraction, this is not a new concept.

Before the expressive power and convenience of Spring Data's Repository abstraction, application developers would use the DAO pattern to abstract out the CRUD and other data access operations (e.g. Querying) from their application services-tier.

However, what Spring Data gives you is the power to do this by simply declaring the contract (a Java interface) for the permitted data access operations and Spring Data (including the provider specific implementations, like Spring Data GemFire) takes cares of the rest, plugging in a "default" data store specific implementation, which is highly customizable.

Obviously, I am biased, but to express a Query using the name of a interface method, using the parameters of the method as SQL/OQL/etc query arguments, is just wicked cool, and powerful.

If the queries are not to complex or specific, this could be easily migrated from 1 data store to another, even between a relation and Key/Value store (like GemFire given the similarities between SQL and OQL, for instance).

Hope this helps. Cheers!

John Blum
  • 7,381
  • 1
  • 20
  • 30
  • that was very helpful, especially the comparison of code between, with and without the use of Templates.. so if i understand correctly from the previous answer. Ideally CRUDOperations in the SpringData provides the abstraction and we go to templates for accessing additional underlying APIs. At a high level, can i summarize as this ? – yathirigan Mar 16 '15 at 17:58