ThinkChat🤖让你学习和工作更高效,注册即送10W Token,即刻开启你的AI之旅 广告
# 使用R2DBC访问数据 本指南将引导您完成构建使用Spring Data R2DBC的应用程序的过程,该应用程序使用反应性数据库驱动程序在关系数据库中存储和检索数据。 ## 你会建立什么 您将构建一个应用程序来存储 `Customer` 基于内存的数据库中的POJO(普通的旧Java对象)。 ## 你需要什么 * 约15分钟 * 最喜欢的文本编辑器或IDE * [JDK 1.8](http://www.oracle.com/technetwork/java/javase/downloads/index.html) 或更高版本 * [Gradle 4+](http://www.gradle.org/downloads) 或 [Maven 3.2+](https://maven.apache.org/download.cgi) * 您还可以将代码直接导入到IDE中: * [弹簧工具套件(STS)](https://spring.io/guides/gs/sts) * [IntelliJ IDEA](https://spring.io/guides/gs/intellij-idea/) ## 如何完成本指南 像大多数Spring 一样 [入门指南](https://spring.io/guides) ,您可以从头开始并完成每个步骤,也可以绕过您已经熟悉的基本设置步骤。 无论哪种方式,您最终都可以使用代码。 要 **从头开始** ,请继续进行“ [从Spring Initializr开始”](https://spring.io/guides/gs/accessing-data-r2dbc/#scratch) 。 要 **跳过基础知识** ,请执行以下操作: * [下载](https://github.com/spring-guides/gs-accessing-data-r2dbc/archive/master.zip) 并解压缩本指南的源存储库,或使用 对其进行克隆 [Git](https://spring.io/understanding/Git) : `git clone [https://github.com/spring-guides/gs-accessing-data-r2dbc.git](https://github.com/spring-guides/gs-accessing-data-r2dbc.git)` * 光盘进入 `gs-accessing-data-r2dbc/initial` * 跳转以 [定义Schema](https://spring.io/guides/gs/accessing-data-r2dbc/#initial) 。 **完成后** ,您可以根据中的代码检查结果 `gs-accessing-data-r2dbc/complete`. ## 从Spring Initializr开始 如果您使用Maven,请访问 [Spring Initializr](https://start.spring.io/#!type=maven-project&language=java&platformVersion=2.4.3.RELEASE&packaging=jar&jvmVersion=1.8&groupId=com.example&artifactId=accessing-data-r2dbc&name=accessing-data-r2dbc&description=Demo%20project%20for%20Spring%20Boot&packageName=com.example.accessing-data-r2dbc&dependencies=data-r2dbc,h2) 以生成具有所需依赖项的新项目(Spring Data R2DBC和H2数据库)。 以下清单显示了 `pom.xml` 选择Maven时创建的文件: ~~~ <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.4.3</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.example</groupId> <artifactId>accessing-data-r2dbc</artifactId> <version>0.0.1-SNAPSHOT</version> <name>accessing-data-r2dbc</name> <description>Demo project for Spring Boot</description> <properties> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-r2dbc</artifactId> </dependency> <dependency> <groupId>com.h2database</groupId> <artifactId>h2</artifactId> <scope>runtime</scope> </dependency> <dependency> <groupId>io.r2dbc</groupId> <artifactId>r2dbc-h2</artifactId> <scope>runtime</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>io.projectreactor</groupId> <artifactId>reactor-test</artifactId> <scope>test</scope> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project> ~~~ 如果您使用Gradle,请访问 [Spring Initializr](https://start.spring.io/#!type=gradle-project&language=java&platformVersion=2.4.3.RELEASE&packaging=jar&jvmVersion=1.8&groupId=com.example&artifactId=accessing-data-r2dbc&name=accessing-data-r2dbc&description=Demo%20project%20for%20Spring%20Boot&packageName=com.example.accessing-data-r2dbc&dependencies=data-r2dbc,h2) 以生成具有所需依赖项的新项目(Spring Data R2DBC和H2数据库)。 以下清单显示了 `build.gradle`选择Gradle时创建的文件: ~~~ plugins { id 'org.springframework.boot' version '2.4.3' id 'io.spring.dependency-management' version '1.0.11.RELEASE' id 'java' } group = 'com.example' version = '0.0.1-SNAPSHOT' sourceCompatibility = '1.8' repositories { mavenCentral() } dependencies { implementation 'org.springframework.boot:spring-boot-starter-data-r2dbc' runtimeOnly 'com.h2database:h2' runtimeOnly 'io.r2dbc:r2dbc-h2' testImplementation 'org.springframework.boot:spring-boot-starter-test' testImplementation 'io.projectreactor:reactor-test' } test { useJUnitPlatform() } ~~~ ### 手动初始化(可选) 如果要手动初始化项目而不是使用前面显示的链接,请按照以下步骤操作: 1. 导航到 [https://start.spring.io](https://start.spring.io) 。 该服务提取应用程序所需的所有依赖关系,并为您完成大部分设置。 2. 选择Gradle或Maven以及您要使用的语言。 本指南假定您选择了Java。 3. 单击 **Dependencies,** 然后选择 **Spring Data R2DBC** 和 **H2 Database** 。 4. 点击 **生成** 。 5. 下载生成的ZIP文件,该文件是使用您的选择配置的Web应用程序的存档。 如果您的IDE集成了Spring Initializr,则可以从IDE中完成此过程。 ## 定义架构 在此示例中,您存储 `Customer`对象,每个对象都标注为R2DBC实体。 以下清单显示了SQL模式类(在 `src/main/resources/schema.sql`): ~~~ CREATE TABLE customer (id SERIAL PRIMARY KEY, first_name VARCHAR(255), last_name VARCHAR(255)); ~~~ 在这里你有一个 `customer` 三列表格: `id`, `first_name`, 和 `last_name`。 这 `id`列是自动递增的,其他列遵循默认的蛇格命名方案。 稍后,我们需要注册一个 `ConnectionFactoryInitializer` 拿起 `schema.sql`应用程序启动期间初始化文件以初始化数据库模式。 由于H2驱动程序位于类路径上,并且我们尚未指定连接URL,因此Spring Boot会启动一个嵌入式H2数据库。 ## 定义一个简单实体 在此示例中,您存储 `Customer`对象,每个对象都标注为R2DBC实体。 以下清单显示了Customer类(在 `src/main/java/com/example/accessingdatar2dbc/Customer.java`): ~~~ package com.example.accessingdatar2dbc; import org.springframework.data.annotation.Id; public class Customer { @Id private Long id; private final String firstName; private final String lastName; public Customer(String firstName, String lastName) { this.firstName = firstName; this.lastName = lastName; } public Long getId() { return this.id; } public void setId(Long id) { this.id = id; } public String getFirstName() { return this.firstName; } public String getLastName() { return this.lastName; } @Override public String toString() { return String.format( "Customer[id=%d, firstName='%s', lastName='%s']", id, firstName, lastName); } } ~~~ 在这里你有一个 `Customer` 具有三个属性的类: `id`, `firstName`, 和 `lastName`。 这 `Customer`类被最小限度地注释。 这 `id` 属性带有注释 `@Id`以便Spring Data R2DBC可以识别主键。 默认情况下,假定主键由数据库在以下位置生成 `INSERT`. 其他两个属性, `firstName` 和 `lastName`,不加注解。 假定它们映射到与属性本身共享相同名称的列。 方便的 `toString()` 方法打印出客户的属性。 ## 创建简单查询 Spring Data R2DBC专注于使用R2DBC作为底层技术在关系数据库中存储数据。 它最引人注目的功能是可以在运行时从存储库界面创建存储库实现的功能。 要了解它是如何工作的,请创建一个与 `Customer` 实体如下清单(在 `src/main/java/com/example/accessingdatar2dbc/CustomerRepository.java`)显示: ~~~ package com.example.accessingdatar2dbc; import org.springframework.data.r2dbc.repository.Query; import org.springframework.data.repository.reactive.ReactiveCrudRepository; import reactor.core.publisher.Flux; public interface CustomerRepository extends ReactiveCrudRepository<Customer, Long> { @Query("SELECT * FROM customer WHERE last_name = :lastname") Flux<Customer> findByLastName(String lastName); } ~~~ `CustomerRepository` 扩展 `ReactiveCrudRepository`界面。 与其一起使用的实体和ID的类型, `Customer` 和 `Long`,是在的通用参数中指定的 `ReactiveCrudRepository`。 通过扩展 `ReactiveCrudRepository`, `CustomerRepository` 继承了几种使用的方法 `Customer` 持久性,包括保存,删除和查找的方法 `Customer`使用反应类型的实体。 Spring Data R2DBC还允许您通过使用其他注释方法来定义其他查询方法 `@Query`。 例如, `CustomerRepository` 包括 `findByLastName()` 方法。 在典型的Java应用程序中,您可能希望编写一个实现 `CustomerRepository`。 但是,这就是使Spring Data R2DBC如此强大的原因:您无需编写存储库接口的实现。 当您运行应用程序时,Spring Data R2DBC将创建一个实现。 现在,您可以连接此示例并查看其外观! ## 创建一个应用程序类 Spring Initializr为应用程序创建一个简单的类。 以下清单显示了Initializr为此示例创建的类(在 `src/main/java/com/example/accessingdatar2dbc/AccessingDataR2dbcApplication.java`): ~~~ package com.example.accessingdatar2dbc; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class AccessingDataR2dbcApplication { public static void main(String[] args) { SpringApplication.run(AccessingDataR2dbcApplication.class, args); } } ~~~ `@SpringBootApplication` 是一个方便注释,它添加了以下所有内容: * `@Configuration`:将类标记为应用程序上下文的Bean定义的源。 * `@EnableAutoConfiguration`:告诉Spring Boot根据类路径设置,其他bean和各种属性设置开始添加bean。 例如,如果 `spring-webmvc` 在类路径上,此注释将应用程序标记为Web应用程序并激活关键行为,例如设置 `DispatcherServlet`. * `@ComponentScan`:告诉Spring在服务器中寻找其他组件,配置和服务 `com/example` 包,让它找到控制器。 这 `main()` 方法使用Spring Boot的 `SpringApplication.run()`启动应用程序的方法。 您是否注意到没有一行XML? 没有 `web.xml`文件。 该Web应用程序是100%纯Java,因此您无需处理任何管道或基础结构。 现在,您需要修改Initializr为您创建的简单类。 为了获得输出(在本例中为控制台),您需要设置一个记录器。 然后,您需要设置初始化程序以设置模式和一些数据,并使用它来生成输出。 以下清单显示了成品 `AccessingDataR2dbcApplication` 类(在 `src/main/java/com/example/accessingdatar2dbc/AccessingDataR2dbcApplication.java`): ~~~ package com.example.accessingdatar2dbc; import io.r2dbc.spi.ConnectionFactory; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.boot.CommandLineRunner; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.annotation.Bean; import org.springframework.core.io.ClassPathResource; import org.springframework.data.r2dbc.connectionfactory.init.ConnectionFactoryInitializer; import org.springframework.data.r2dbc.connectionfactory.init.ResourceDatabasePopulator; import java.time.Duration; import java.util.Arrays; @SpringBootApplication public class AccessingDataR2dbcApplication { private static final Logger log = LoggerFactory.getLogger(AccessingDataR2dbcApplication.class); public static void main(String[] args) { SpringApplication.run(AccessingDataR2dbcApplication.class, args); } @Bean ConnectionFactoryInitializer initializer(ConnectionFactory connectionFactory) { ConnectionFactoryInitializer initializer = new ConnectionFactoryInitializer(); initializer.setConnectionFactory(connectionFactory); initializer.setDatabasePopulator(new ResourceDatabasePopulator(new ClassPathResource("schema.sql"))); return initializer; } @Bean public CommandLineRunner demo(CustomerRepository repository) { return (args) -> { // save a few customers repository.saveAll(Arrays.asList(new Customer("Jack", "Bauer"), new Customer("Chloe", "O'Brian"), new Customer("Kim", "Bauer"), new Customer("David", "Palmer"), new Customer("Michelle", "Dessler"))) .blockLast(Duration.ofSeconds(10)); // fetch all customers log.info("Customers found with findAll():"); log.info("-------------------------------"); repository.findAll().doOnNext(customer -> { log.info(customer.toString()); }).blockLast(Duration.ofSeconds(10)); log.info(""); // fetch an individual customer by ID repository.findById(1L).doOnNext(customer -> { log.info("Customer found with findById(1L):"); log.info("--------------------------------"); log.info(customer.toString()); log.info(""); }).block(Duration.ofSeconds(10)); // fetch customers by last name log.info("Customer found with findByLastName('Bauer'):"); log.info("--------------------------------------------"); repository.findByLastName("Bauer").doOnNext(bauer -> { log.info(bauer.toString()); }).blockLast(Duration.ofSeconds(10));; log.info(""); }; } } ~~~ 这 `AccessingDataR2dbcApplication` 类包括一个 `main()` 的方法 `CustomerRepository`通过一些测试。 首先,它获取 `CustomerRepository`从Spring应用程序上下文中。 然后节省了 `Customer` 对象,展示了 `save()`方法并设置一些要使用的数据。 接下来,它调用 `findAll()` 取全部 `Customer`数据库中的对象。 然后它调用 `findById()` 取一个 `Customer`通过其ID。 最后,它调用 `findByLastName()`查找姓氏为“宝华”的所有客户。 R2DBC是一种反应式编程技术。 同时,我们在同步的命令式流程中使用它,这就是为什么我们需要将每个调用与的变体进行同步 `block(…)`方法。 在典型的无功应用中, `Mono` 或者 `Flux` 表示操作员管道,该操作员管道被退回到Web控制器或事件处理器,后者订阅反应性序列而不会阻塞调用线程。 默认情况下,Spring Boot启用R2DBC存储库支持并在包(及其子包)中查找 @SpringBootApplication位于。 如果您的配置在不可见的程序包中有R2DBC存储库接口定义,则可以使用以下方法指出备用程序包 @EnableR2dbcRepositories 及其类型安全 basePackageClasses=MyRepository.class 范围。 ## 建立可执行的JAR 您可以使用Gradle或Maven从命令行运行该应用程序。 您还可以构建一个包含所有必需的依赖项,类和资源的可执行JAR文件,然后运行该文件。 生成可执行jar使得在整个开发生命周期中,跨不同环境等等的情况下,都可以轻松地将服务作为应用程序进行发布,版本控制和部署。 如果您使用Gradle,则可以通过使用以下命令运行该应用程序 `./gradlew bootRun`。 或者,您可以通过使用以下命令构建JAR文件: `./gradlew build` 然后运行JAR文件,如下所示: ~~~ java -jar build/libs/gs-accessing-data-r2dbc-0.1.0.jar ~~~ 如果您使用Maven,则可以通过使用以下命令运行该应用程序 `./mvnw spring-boot:run`。 或者,您可以使用以下命令构建JAR文件: `./mvnw clean package` 然后运行JAR文件,如下所示: ~~~ java -jar target/gs-accessing-data-r2dbc-0.1.0.jar ~~~ 此处描述的步骤将创建可运行的JAR。 您还可以 构建经典的WAR文件 。 运行应用程序时,应该看到类似于以下内容的输出: ~~~ == Customers found with findAll(): Customer[id=1, firstName='Jack', lastName='Bauer'] Customer[id=2, firstName='Chloe', lastName='O'Brian'] Customer[id=3, firstName='Kim', lastName='Bauer'] Customer[id=4, firstName='David', lastName='Palmer'] Customer[id=5, firstName='Michelle', lastName='Dessler'] == Customer found with findOne(1L): Customer[id=1, firstName='Jack', lastName='Bauer'] == Customer found with findByLastName('Bauer'): Customer[id=1, firstName='Jack', lastName='Bauer'] Customer[id=3, firstName='Kim', lastName='Bauer'] ~~~ ## 概括 恭喜你! 您已经编写了一个简单的应用程序,该应用程序使用Spring Data R2DBC将对象保存到数据库中并从数据库中获取对象,而所有这些都无需编写具体的存储库实现。