在上一个范例中,是写死回传的内容,显然在现实生活中应该是不会有公司让你可以这样做的,而当我们的Controller
开始Reactive了,背後的data store当然也要reactive起来。
一开始的时候其实Spring WebFlux
并不支援关联式资料库,只能使用NoSQL
或是Redis
,但还是有许多的业务场景是更适合使用RDB
的,这时候Spring
推出 Reactive Relational Database Connectivity
简称R2DBC
,跟JDBC
一样是DB driver
,但它并不是建立在JDBC
或是其他api之上,因为JDBC
是blocking的api,最後与我们熟悉的Spring Data
结合成为 Spring Data R2DBC
。
build.gralde
多补上两个dependencies
implementation 'org.springframework.boot:spring-boot-starter-data-r2dbc'
runtimeOnly 'dev.miku:r2dbc-mysql'
这次开始的范例需要用到mySql,这边提供docker image(docker hub)的版本,
init.sql
须放在与stack.yml
同一层
CREATE DATABASE IF NOT EXISTS test;
USE test;
stack.yml
主要就是有一个可以init的sql执行以及有一个8081的ui介面。
# Use root/example as user/password credentials
version: '3.1'
services:
db:
image: mysql
command: --default-authentication-plugin=mysql_native_password --init-file /data/application/init.sql
restart: always
volumes:
- ./init.sql:/data/application/init.sql
environment:
MYSQL_ROOT_PASSWORD: example
ports:
- 3306:3306
adminer:
image: adminer
restart: always
ports:
- 8081:8080
application.properties
将设定帐号密码同上面DB设定
spring.r2dbc.url=r2dbc:mysql://localhost:3306/test
spring.r2dbc.username=root
spring.r2dbc.password=example
Greeting.java
Entity
,跟Spring data
相同,有@Id
就会自然被Spring视作为DB物件。
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Greeting {
@Id
private Long id;
private String message;
public Greeting(String message) {
this.message = message;
}
}
GreetingRepository
Repository 一样有很方便的CrudRepository
可以使用,用法基本上是一样的。
public interface GreetingRepository extends ReactiveCrudRepository<Greeting, Long> {
Mono<Greeting> findById(Long id);
Flux<Greeting> findAll();
Flux<Greeting> findByMessage(String message);
Mono<Void> save(Mono<Greeting> greeting);
}
\src\main\resources\schema.sql
看文件没有找到会自动产生table,可能还没支援,不过有提供ini.sql
的方式,先准备schema.sql
在resource目录下
CREATE TABLE IF NOT EXISTS greeting (id bigint PRIMARY KEY AUTO_INCREMENT, message VARCHAR(255));
在任意地方放上这个initializer
,建议是可以放在命名为DbConfiguration
之类的地方统一管理,这边测试就直接放在WebFluxGuideApplication
底下
@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(GreetingRepository repository) {
return (args) -> {
// save a few Greeting
repository
.saveAll(
Arrays.asList(
new Greeting("Hello"),
new Greeting("Hello"),
new Greeting("Yo"),
new Greeting("Nice to meet you"),
new Greeting("Hi")))
.blockLast(Duration.ofSeconds(10));
// fetch all Greeting
log.info("Greeting found with findAll():");
log.info("-------------------------------");
repository
.findAll()
.doOnNext(
greeting -> {
log.info(greeting.toString());
})
.blockLast(Duration.ofSeconds(10));
log.info("");
// fetch an individual Greeting by ID
repository
.findById(1L)
.doOnNext(
greeting -> {
log.info("Greeting found with findById(1L):");
log.info("--------------------------------");
log.info(greeting.toString());
log.info("");
})
.block(Duration.ofSeconds(10));
// fetch Greeting by last name
log.info("Greeting found with findByMessage('Hello'):");
log.info("--------------------------------------------");
repository
.findByMessage("Hello")
.doOnNext(
hello -> {
log.info(hello.toString());
})
.blockLast(Duration.ofSeconds(10));
log.info("");
};
}
今天简单的将Reactive Programming推进到了DB的世界,下一篇会补充说明。
Projucer 支援另一类型的专案——Animated。与一般的 GUI 专案不同处之一是,Mai...
今天要来跟各位一起解析 QnA Maker Bot,以下简称 QA Bot。 今天是参考 官方范例程...
前言 这篇跟工程师其实没那麽有关,适合给新手leader定OKRs的时候看看。 演讲总结 今天要讲...
既然前几篇介绍了外部中断、Timer中断与USART,那接下来就结合这三种中断来模拟红绿灯出来吧。 ...
图片来源 谈了好几天的AI相关议题, 其实主要也是因为之前的分享中有提到, 我是偶然间在今年七月初...