12.2.4 编写响应式 Cassandra 库
正如您在第 3 章中看到的,编写一个基于 Spring Data 的 Repository,只需要声明扩展自 Spring Data 的基础接口。以及有选择性地,声明一些自定义查询的其他查询方法。事实证明,编写响应式 Repository 也没有什么不同。主要的区别是,要扩展不同的接口。您的方法将要处理响应式的 Mono 和 Flux,而不是实体类型和集合。
在编写响应式 Cassandra Repository 时,您可以选择继承两个基本接口:ReactiveCassandraRepository
和 ReactiveCrudRepository
。我们的选择主要取决于 Repository 的使用方式。ReactiveCassandraRepository
扩展了 ReactiveCrudRepository
,提供了 insert()
的一些重载方法。当要保存的对象是新建对象时,该方法会进行一些优化。其他方面,ReactiveCassandraRepository
提供与 ReactiveCrudepository
相同的操作。如果要插入大量的数据,您可能会选择ReactiveCassandraRepository
。否则,最好使用 ReactiveCrudRepository
,因为它在兼容其他数据库类型上更方便。
我的 Cassandra Repository 必须是响应式的吗?
尽管本章描述的,是使用 Spring Data 编写响应式 Repository,但是您可能也有兴趣了解一下,其实也可以为 Cassandra 编写非响应式的 Repository。非响应式 Repository 需要扩展
CassandraRepository
接口,而不是扩展ReactiveCassandraRepository
或ReactiveCrudRepository
接口。然后您的 Repository 方法,可以简单地返回添加了 Cassandra 注解的实体类型或这些类型的集合,而不是 Flux 和 Mono。如果您决定使用非响应式 Repository,还可以更改依赖,改为依赖于
spring-boot-starter-data-cassandra
而不是spring-bootstarter-data-cassandra-reactive
,虽然并不强制您要这样做。
先来看一下,您为 Taco Cloud 应用程序已经编写的一些 Repository。要让这些 Repository 变成响应式的,您应该做的第一个修改是,变更它们的父类。让它们扩展 ReactiveCrudRepository
或 ReactiveCassandraRepository
, 而不是 CrudRepository
。例如,对 IngredientRepository
来说,除了初始化数据库之外,您不会插入很多新的数据。因此,可以直接修改父类接口为 RectiveCrudRepository
,如图所示:
您从未在 IngredientRepository 中定义任何自定义查询方法,因此使 IngredientRepository 成为响应应式 Repository 没有什么更多的工作。但是,因为它现在扩展了 ReactiveCrudRepository
,所以它的方法将处理 Flux 和 Mono。例如 findAll()
方法,现在返回 Flux<Ingredient>
而不是 Iterable<Ingredient>
。因此,您需要确保,无论在何处都以正确的方式使用数据。例如,IngredientController
中的 allIngredients()
方法需要重写,以返回 Flux<Ingredient>
:
对 TacoRepository
的修改,只是细节上更复杂一些。首先不再扩展 PagingAndSortingRepository
接口,而是扩展 ReactiveCassandraRepository
。另外 Taco 对象的 ID 属性,也不再是 Long 型,而是 UUID:
因为这个新的 TacoRepository 的 findAll()
方法返回 Flux<Ingredient>
,您不再费心考虑扩展 PagingAndSortingRepository
以处理分页。相反,DesignTacoController
中的 recentTacos()
方法只需要对返回的 Flux 调用 take()
方法,以限制数量。(事实上,在 11.1.2 节,您已经对 DesignTacoController
的 recentTacos()
方法进行了修改)
对 OrderRepository
所需做的更改也很简单。不再扩展 CrudRepository
,而是扩展 ReactiveCassandraRepository
:
最后,让我们看看 UserRepository
。您还记得,UserRepository
有一个自定义的查询方法 findByUsername()
。这个方法给您的 Cassandra 持久化修改带来一点困难。应该像如下这样修改:
所有接口所做的修改都基本一样(除了 IngredientRepository
),现在 UserRepository
也扩展了 ReactiveCassandraRepository
,看起来都很正常。但是它的 findByUsername()
方法需要引起额外注意。
首先,因为这是响应式的,所以 findByUsername()
不能再返回简单的实体对象 User。需要重新定义它以返回 Mono<User>
。一般来说,您在任何一个响应式的自定义查询方法中,都应该返回一个 Mono(如果没有多个值)或 Flux (如果返回了多个值)。
另外,Cassandra 的特性决定了,您不能像关系型数据库 SQL 查询中那样,简单地使用 where 子句。 Cassandra 对读取数据高度优化,使用 where 子句进行过滤,可能会减慢一个本来很快速的查询。即便如此,对查询结果所在的表,按一个或多个列过滤,可能在业务上是必要的。这种情况下,使用 @AllowFiltering
注解标识允许过滤结果,为这些特殊情况提供解决办法。
在 findByUsername()
中,您可能希望看到如下 CQL 查询:
再说一遍,这是 Cassandra 不允许的。但是当 @AllowFiltering
注解加在 findByUsername()
上,会得到如下所示的 CQL 查询:
查询末尾的 allow filtering 子句,提醒 Cassandra 您知道,这会对查询性能有潜在影响,但您仍然需要它。在这种情况下,Cassandra 将允许 where 子句并相应地过滤结果。
Cassandra 很强大,当它与 Spring Data 和 Reactor 结合,您就可以在 Spring 应用程序中体验到这些强大功能。现在让我们转移注意力,来看看另一个对响应式 Repository 支持的数据库:MongoDB。
最后更新于