Spring Data的目的是什么?它的抽象程度如何?

时间:2015-03-10 11:47:17

标签: spring spring-data spring-data-gemfire spring-data-redis

在尝试理解“Spring Data”的目的时,我遇到了这篇文章,并尝试了几个Gemfire / Redis存储库及其相应的Spring-Data组件的示例。有人可以帮助我解决以下问题。

方案 : 当GemFire是我的数据存储区时,我必须在GemFireTemplate上使用 创建,获取和删除 方法来执行CRUD操作。 当Redis是我的数据存储区时,我不得不在RedisTemplate上使用方法 .opsForHash()。put,.opsForHash()。get和.opsForHash()。delete 来执行相同的CRUD操作。

问题

  

不是Spring-Data应该提供一定程度的抽象   底层数据存储?如果我希望知道相应的CRUD   方法并具有基于底层数据存储的不同API,   Spring-Data组件带来了什么样的抽象?不能   我直接使用Jedis或Java客户端进行Gemfire来执行这些操作   datatstore特定的CRUD操作?

This link似乎解释了这一点,但看起来我需要一些帮助来理解它。

所有持久性商店都没有通用API。差异太基础了。但Spring Data项目确实提供了一种访问数据的通用编程模型

3 个答案:

答案 0 :(得分:6)

感谢您提出的问题,因为Master Slave已经很好地指出了Spring Data的好处 提供的是多方面的,但有时在商店模块之间支持的功能意义上存在功能差异。那些是 部分原因是特定底层数据存储的不同特性和功能以及焦点和时间限制。

Redis和Gemfire通过提供类似存储和访问模型的键值来扩展类似的商店技术。但是,Gemfire提供了比Redis更丰富的查询功能。这就是原因之一 Spring Data Gemfire已经有Repository abstraction了很长一段时间。

另一方面,Redis是一个不同的故事 - 正如奴隶大师已经提到的,你可以轻松地建立自己的定制Redis存储库 - 这就是 很多人都这样做 - 但通常与Redis的交互对于用例来说非常独特,所以我们没有看到 这种功能重叠很多,可以激发一种通用的实现方式,而不仅仅是“保存”#34;和"加载"。

我们有一个ticket用于向Spring Data Redis添加存储库抽象,但我们还没有时间去做。

答案 1 :(得分:3)

Spring数据确实为底层数据存储提供了一定程度的抽象。但是,NoSQL存储是一个非常多样化的频谱,一个是图形数据库,另一个是专门用于存储文档,第三个用于存储键值对等。尽管如此,这些并不是你要抽象出来的差异,这些是这一独特功能让您首先选择它们。

另一方面,Spring Data为您提供了一致性,并且可以针对这些不同的商店应用已知模式

  • 它为您提供了一种配置资源以访问商店的方法
  • 底层类型和Java类型之间的映射和转换
  • 大多数商店的存储库抽象,归结为仅声明基本CRUD操作的接口。实现和特定于商店的东西由Spring Data
  • 处理
  • Dedicate模板实现,提供访问本机API的回调

列表还在继续。关键是Spring Data确实提供了尽可能多的抽象级别,但它也没有将公开的功能限制在最不为人所知的共同点,因为这会剥夺不同商店的好处。 / p>

答案 2 :(得分:3)

关于这个问题的一些额外想法...

使用Spring模板进行特定于数据存储的访问(例如GemfireTemplate)的众多优势之一就是它们可以保护开发人员免受模板通常包装的基础数据存储API更改的影响。如果数据存储供应商使API接口发生变化(GemFire就是这种情况),那么模板可以为底层API提供一层抽象/适应,而无需更改用户应用程序。

此外,模板可以利用其他Spring Infrastructure Management,例如通常不会内置于underly数据存储API本身的事务。模板还可以为底层数据存储产品中的多个不同API提供外观和便利层。

例如,GemfireTemplate将操作封装为“获取”和“放置”数据以及“查询”感兴趣的数据。

要在GemFire中执行前者,您需要执行以下操作...

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

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

在查询“/示例”中的数据时,您会......

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
}

现在,将其与Spring模板进行对比以获取/放置数据

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

并查询......

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

// process the query results

如果发生异常,或者无法收集结果,那么GemFires的异常/错误统一映射到core Spring Framework DAO Exception hierarchy,这是另一个优势,可以更轻松地切换数据存储,以及一致的事务处理

最后,尽管Thomas Darimont和Master Slave都很好地总结了使用Spring Data Repository abstraction的优点,但这并不是一个新概念。

在Spring Data的Repository抽象的表达能力和便利之前,应用程序开发人员将使用DAO模式从其应用程序服务层抽象出CRUD和其他数据访问操作(例如查询)。

然而,Spring Data为您提供的功能是通过简单地声明允许的数据访问操作的合同(Java接口)和Spring Data(包括提供者特定的实现,如Spring Data GemFire)来实现这一目标。其余的,插入“默认”数据存储特定实现,高度customizable

显然,我有偏见,但是使用接口方法的名称来表达查询,使用方法的参数作为SQL / OQL / etc查询参数,只是邪恶酷炫,功能强大。

如果查询不复杂或具体,那么这可以很容易地从1个数据存储迁移到另一个,甚至在关系和键/值存储之间(例如,鉴于SQL和OQL之间的相似性,就像GemFire)。 / p>

希望这会有所帮助。干杯!