原标题:Spring认证中国教育管理中心-Spring Data R2DBC框架教程二(Spring中国教育管理中心)
13.4.R2dbcEntityOperations 数据访问 API
R2dbcEntityTemplate是 Spring Data R2DBC 的中心入口点。它为典型的临时用例(例如查询、插入、更新和删除数据)提供了直接面向实体的方法和更窄、更流畅的接口。
入口点(insert()、select()、update()和其他)遵循基于要运行的操作的自然命名模式。从入口点开始,API 旨在仅提供依赖于上下文的方法,这些方法导致创建和运行 SQL 语句的终止方法。Spring Data R2DBC 使用R2dbcDialect抽象来确定绑定标记、分页支持和底层驱动程序本机支持的数据类型。
所有终端方法总是返回一个Publisher代表所需操作的类型。实际语句在订阅时发送到数据库。
13.4.1.插入和更新实体的方法
有几种方便的方法可R2dbcEntityTemplate用于保存和插入对象。为了对转换过程进行更细粒度的控制,您可以注册 Spring 转换器R2dbcCustomConversions ——例如Converter<Person, OutboundRow>和Converter<Row, Person>。
使用保存操作的简单情况是保存一个 POJO。在这种情况下,表名由类的名称(非完全限定)确定。您还可以使用特定的集合名称调用保存操作。您可以使用映射元数据来覆盖存储对象的集合。
插入或保存时,如果Id未设置该属性,则假设其值将由数据库自动生成。因此,对于自动生成,类中的Id属性或字段的类型必须是Long, 或Integer。
以下示例显示了如何插入一行并检索其内容:
示例 55. 使用 R2dbcEntityTemplate
Person person = new Person("John", "Doe"); Mono<Person> saved = template.insert(person); Mono<Person> loaded = template.selectOne(query(where("firstname").is("John")), Person.class);
以下插入和更新操作可用:
也可以使用一组类似的插入操作:
Mono<T> insert (T objectToSave):将对象插入到默认表中。
Mono<T> 更新 (T objectToSave):将对象插入到默认表中。
可以使用 fluent API 自定义表名。
13.4.2.选择数据
的select(…)和selectOne(…)在方法R2dbcEntityTemplate被用来从表中选择的数据。这两种方法都采用一个Query定义字段投影、WHERE子句、ORDER BY子句和限制/偏移分页的对象。无论底层数据库如何,限制/偏移功能对应用程序都是透明的。R2dbcDialect抽象支持此功能以迎合各个 SQL 风格之间的差异。
示例 56. 使用 R2dbcEntityTemplate
Flux<Person> loaded = template.select(query(where("firstname").is("John")), Person.class);
13.4.3.流利的API
本节解释了 fluent API 的用法。考虑以下简单查询:
Flux<Person> people = template.select(Person.class) .all();
Person与select(…)方法一起使用将表格结果映射到Person结果对象上。
获取all()行返回一个Flux<Person>没有限制的结果。
以下示例声明了一个更复杂的查询,该查询按名称、WHERE条件和ORDER BY子句指定表名:
Mono<Person> first = template.select(Person.class) .from("other_person") .matching(query(where("firstname").is("John") .and("lastname").in("Doe", "White")) .sort(by(desc("id")))) .one();
按名称从表中选择返回使用给定域类型的行结果。
发出的查询WHERE在firstname和lastname列上声明条件以过滤结果。
结果可以按单独的列名排序,从而产生一个ORDER BY子句。
选择一个结果只会获取一行。这种使用行的方式期望查询准确返回单个结果。
如果查询产生多个结果,则Mono发出 a
IncorrectResultSizeDataAccessException。
您可以通过提供目标类型直接将投影应用于结果select(Class<?>)。
您可以通过以下终止方法在检索单个实体和检索多个实体之间切换:
first(): 只消费第一行,返回一个Mono. Mono如果查询没有返回结果,则返回完成而不发出对象。
one(): 只消耗一行,返回一个Mono. Mono如果查询没有返回结果,则返回完成而不发出对象。如果查询返回多于一行,则Mono异常完成发射IncorrectResultSizeDataAccessException。
all():使用所有返回的行返回一个Flux.
count():应用计数投影返回Mono<Long>。
exists(): 通过返回返回查询是否产生任何行Mono<Boolean>。
您可以使用select()入口点来表达您的SELECT查询。结果SELECT查询支持常用的子句(WHERE和ORDER BY)并支持分页。流畅的 API 风格让您可以将多个方法链接在一起,同时拥有易于理解的代码。为了提高可读性,您可以使用静态导入来避免使用“new”关键字来创建Criteria实例。
Criteria 类的方法
的Criteria类提供了以下的方法,所有这些都对应于SQL操作符:
Criteria and (String column) : 将一个Criteria与指定的链接添加property到当前Criteria并返回新创建的一个。
Criteria 或 (String column):将Criteria指定的链添加property到当前Criteria并返回新创建的。
Criteria GreaterThan (Object o):使用>运算符创建条件。
Criteria GreaterThanOrEquals (Object o):使用>=运算符创建条件。
Criteria in (Object… o):通过IN对 varargs 参数使用运算符来创建条件。
Criteria in (Collection<?> collection):通过使用IN集合的运算符创建条件。
Criteria is (Object o):通过使用列匹配 ( property = value)创建一个条件。
Criteria isNull ():使用IS NULL运算符创建条件。
Criteria isNotNull ():使用IS NOT NULL运算符创建条件。
Criteria lessThan (Object o):使用<运算符创建条件。
Criteria lessThanOrEquals (Object o):使用⇐运算符创建条件。
Criteria like (Object o):通过使用LIKE运算符创建一个条件,而不进行转义字符处理。
Criteria not (Object o):使用!=运算符创建条件。
Criteria notIn (Object… o):通过NOT IN对 varargs 参数使用运算符来创建条件。
Criteria notIn (Collection<?> collection):通过使用NOT IN集合的运算符创建条件。
你可以用Criteria与SELECT,UPDATE和DELETE查询。
13.4.4.插入数据
您可以使用insert()入口点插入数据。
考虑以下简单的类型化插入操作:
Mono<Person> insert = template.insert(Person.class) .using(new Person("John", "Doe"));
Person与into(…)方法一起使用INTO根据映射元数据设置表。它还准备插入语句以接受Person要插入的对象。
提供一个标量Person对象。或者,您可以提供 aPublisher来运行INSERT语句流。此方法提取所有非null值并插入它们。
13.4.5.更新数据
您可以使用update()入口点来更新行。更新数据首先通过接受Update指定的分配来指定要更新的表。它还接受Query创建WHERE子句。
考虑以下简单的类型化更新操作:
Person modified = … Mono<Integer> update = template.update(Person.class) .inTable("other_table") .matching(query(where("firstname").is("John"))) .apply(update("age", 42));
Person根据映射元数据更新对象并应用映射。
通过调用inTable(…)方法设置不同的表名。
指定转换为WHERE子句的查询。
应用Update对象。在这种情况下设置age为42并返回受影响的行数。
13.4.6.删除数据
您可以使用delete()入口点删除行。删除数据以要从中删除的表的规范开始,并且可以选择接受 aCriteria来创建WHERE子句。
考虑以下简单的插入操作:
Mono<Integer> delete = template.delete(Person.class) .from("other_table") .matching(query(where("firstname").is("John"))) .all();
删除Person对象并根据映射元数据应用映射。
通过调用from(…)方法设置不同的表名。
指定转换为WHERE子句的查询。
应用删除操作并返回受影响的行数。
14. R2DBC 存储库
本章指出了 R2DBC 存储库支持的特点。本章以使用 Spring Data Repositories 中解释的核心存储库支持为基础。在阅读本章之前,您应该对那里解释的基本概念有充分的了解。
14.1.用法
要访问存储在关系数据库中的域实体,您可以使用我们复杂的存储库支持,这大大简化了实施。为此,请为您的存储库创建一个界面。考虑以下Person类:
示例 57. 示例 Person 实体
public class Person { @Id private Long id; private String firstname; private String lastname; // … getters and setters omitted}
以下示例显示了上述Person类的存储库接口:
示例 58. 用于持久化 Person 实体的基本存储库接口
public interface PersonRepository extends ReactiveCrudRepository<Person, Long> { // additional custom query methods go here}
要配置 R2DBC 存储库,您可以使用@EnableR2dbcRepositories注释。如果没有配置基础包,基础设施会扫描带注释的配置类的包。以下示例显示了如何对存储库使用 Java 配置:
示例 59. 存储库的 Java 配置
@Configuration@EnableR2dbcRepositoriesclass ApplicationConfig extends AbstractR2dbcConfiguration { @Override public ConnectionFactory connectionFactory() { return … } }
因为我们的域存储库扩展了ReactiveCrudRepository,它为您提供了访问实体的反应式 CRUD 操作。除此之外ReactiveCrudRepository,还有ReactiveSortingRepository,它添加了类似于 的附加排序功能
PagingAndSortingRepository。使用存储库实例只是将其依赖注入客户端的问题。因此,您可以Person使用以下代码检索所有对象:
示例 60. 对 Person 实体的分页访问
@ExtendWith(SpringExtension.class)@ContextConfigurationclass PersonRepositoryTests { @Autowired PersonRepository repository; @Test void readsAllEntitiesCorrectly() { repository.findAll() .as(StepVerifier::create) .expectNextCount(1) .verifyComplete(); } @Test void readsEntitiesByNameCorrectly() { repository.findByFirstname("Hello World") .as(StepVerifier::create) .expectNextCount(1) .verifyComplete(); } }
前面的示例使用 Spring 的单元测试支持创建了一个应用程序上下文,它将基于注解的依赖注入到测试用例中。在测试方法中,我们使用存储库来查询数据库。我们StepVerifier用作测试辅助工具来验证我们对结果的期望。