Spring 数据及其抽象级别的用途是什么?

What is the purpose of Spring Data and its level of Abstraction?

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

场景: 当 GemFire 是我的数据存储区时,我不得不在 GemFireTemplate 上使用方法 create、get 和 remove 来执行 CRUD 操作。 当 Redis 是我的数据存储时,我不得不使用方法 .opsForHash().put 、 .opsForHash().get 和 .opsForHash().delete 在 RedisTemplate 上执行相同的 CRUD 操作。

问题:

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 似乎解释了这一点,但是,看起来我需要一些帮助来理解它。

没有通用的API到所有持久化存储。差异太根本了。但是 Spring 数据项目确实提供了一个通用的编程模型来访问您的数据

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

另一方面,Spring 数据为您提供了一致性以及针对这些不同商店应用已知模式的方法

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

不胜枚举。关键是 Spring Data 确实提供了尽可能多的抽象级别,但它也没有将公开的功能限制为一个最不为人知的公分母,因为这会带走不同商店的好处.

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

Redis 和 Gemfire 通过提供类似于存储和访问模型的键值对来扩展类似的存储技术。然而 Gemfire 提供了比 Redis 丰富得多的查询功能。这就是为什么的原因之一 Spring Data Gemfire 已经 Repository abstraction 很久了。

另一方面,Redis 是另一回事 - 正如 Master Slave 已经提到的,您可以轻松构建自己的自定义 Redis Repository - 就是这样 很多人都这样做 - 但通常与 Redis 的交互对于用例来说是非常独特的,所以我们没有看到 如此多的功能重叠可以激发通用实现,而不仅仅是 "save" 和 "load".

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

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

使用 Spring 模板进行特定于数据存储的访问(例如 GemfireTemplate)的众多优点之一是它们使开发人员免受模板通常围绕的基础数据存储 API 更改的影响。如果数据存储供应商进行 API 接口中断更改(GemFire 就是这种情况),则模板可以向底层 API 提供一层 abstraction/adaption,而无需更改用户应用程序.

此外,该模板可以利用其他 Spring 基础设施管理,例如通常不会固有地内置到底层数据存储 API 中的事务。模板还可以为基础数据存储产品中的几个不同 API 提供外观和便利层。

例如,GemfireTemplate 将操作封装到 'get' 和 'put' 数据以及 'querying' 感兴趣的数据。

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

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

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

查询'/Example'中的数据时,您会...

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 模板与 get/put 数据

进行对比
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 的 Exceptions/Errors 会统一映射到 core Spring Framework DAO Exception hierarchy,还有一个优点,这使得切换底层数据存储更容易,同时具有一致的事务处理。

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

在 Spring 数据存储库抽象的表现力和便利性出现之前,应用程序开发人员会使用 DAO 模式从他们的应用程序服务层中抽象出 CRUD 和其他数据访问操作(例如查询)。

但是,Spring Data 为您提供的是通过简单地为允许的数据访问操作和 Spring Data (包括提供者特定的实现,如 Spring Data GemFire) 负责其余部分,插入 "default" 数据存储特定的实现,这是高度 customizable.

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

如果查询不是太复杂或不具体,这可以很容易地从一个数据存储迁移到另一个,甚至在关系和 Key/Value 存储之间(如 GemFire 考虑到 SQL 之间的相似性)和 OQL,例如)。

希望这对您有所帮助。干杯!