Spring-WebFlux整合Mysql

3,169 阅读2分钟

简介

Spring WebFlux 是 Spring Framework 5.0中引入的新的响应式web框架。与Spring MVC不同,它不需要Servlet API,是完全异步且非阻塞的,并且通过Reactor项目实现了Reactive Streams规范。Spring WebFlux 用于创建基于事件循环执行模型的完全异步且非阻塞的应用程序。

【spring-webmvc + Servlet + Tomcat】命令式的、同步阻塞的
【spring-webflux + Reactor + Netty】响应式的、异步非阻塞的

因此在webflux中平时所用的例如数据库中间件都不跟平时常用的servlet+tomcat这套命令式、同步阻塞的不同。

数据库

在日常开发中使用最多的就是连接数据库,在响应式、异步阻塞的模式中需要使用专门的组件为r2dbc,使用起来很方便。maven中添加依赖

     <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-r2dbc</artifactId>
            <version>2.5.0</version>
     </dependency>
     <!-- https://mvnrepository.com/artifact/com.github.jasync-sql/jasync-r2dbc-mysql -->
        <dependency>
            <groupId>com.github.jasync-sql</groupId>
            <artifactId>jasync-r2dbc-mysql</artifactId>
            <version>1.2.2</version>
        </dependency>

连接mysql则还需要单独导入支持响应式的mysql derive 这里用的是jasync,因为是spring-boot-starter,所以只需要在配置文件中加入以下配置:

  r2dbc:
    url: mysql://%s:%s@rm-xxxx.mysql.rds.aliyuncs.com/database
    username: xxxx
    password: xxxxxxx
    pool:
      enabled: true
      initial-size: 100
      max-size: 200
      max-idle-time: 30m
      validation-query: SELECT 1

很奇怪自动装配不能自动的装配数据库的账号及密码,因此需要手动注入

@Configuration
public class MysqlConfig {

    @Value("${spring.r2dbc.url}")
    private String url;
    @Value("${spring.r2dbc.username}")
    private String username;
    @Value("${spring.r2dbc.password}")
    private String password;

    @Bean
    public R2dbcEntityTemplate r2dbcEntityTemplate(ConnectionFactory connectionFactory) {
        return new R2dbcEntityTemplate(connectionFactory);
    }
    @Bean
    public ConnectionFactory connectionFactory() {
        com.github.jasync.sql.db.Configuration configuration = URLParser.INSTANCE.parseOrDie(String.format(url, username, password), StandardCharsets.UTF_8);
        return new JasyncConnectionFactory(new MySQLConnectionFactory(configuration));
    }
}

将数据库的账号及密码从url传入。然后通过jasync的工厂构建数据库的链接工厂。
其他用法上r2dbc与传统的spring-data-jpa类似
定义实体类:

@Data
@Builder
@Table("demo_user")
public class DemoUser {

    @Id
    private Long id;

    private String name;

    private Integer gender;

    private LocalDateTime updateTime;

    private LocalDateTime createTime;
}

定义repository:

public interface DemoUserRepository extends ReactiveCrudRepository<DemoUser,Long> {
    <S extends T> Mono<S> save(S entity);

	/**
	 * Saves all given entities.
	 *
	 * @param entities must not be {@literal null}.
	 * @return {@link Flux} emitting the saved entities.
	 * @throws IllegalArgumentException in case the given {@link Iterable entities} or one of its entities is
	 *           {@literal null}.
	 */
	<S extends T> Flux<S> saveAll(Iterable<S> entities);

	/**
	 * Saves all given entities.
	 *
	 * @param entityStream must not be {@literal null}.
	 * @return {@link Flux} emitting the saved entities.
	 * @throws IllegalArgumentException in case the given {@link Publisher entityStream} is {@literal null}.
	 */
	<S extends T> Flux<S> saveAll(Publisher<S> entityStream);
    
}

直接继承ReactiveCrudRepository接口,该接口中已经定义好了一些基本的增删改查方法,与传统的命令式编程的区别是返回结果是有响应式编程中特有的Mono或Flux包装的,需要注意的就是需要加上以下注解reository才会生效

@EnableR2dbcRepositories(basePackages = "com.xxx.repository")

然后就像spring-data-jpa一样使用就行

private final DemoUserRepository userRepository;

    @GetMapping("/users")
    public Flux<AiFunction> getUser(){
        return userRepository.findAll();
    }

当然也可以自定义sql

@Query("select * from demo_user where name = :name")
Mono<AiFunction> findByUserName(String name);

未完待续。。。