「Spring Reactive Stack」使用R2DBC访问MySQL

MySQL等一系列的关系型数据库也在R2DBC等包的帮助下支持响应式。
R2DBC基于Reactive Streams反应流规范,它是一个开放的规范,为驱动程序供应商和使用方提供接口(r2dbc-spi),与JDBC的阻塞特性不同,它提供了完全反应式的非阻塞API关系型数据库交互。

  1. 创建Maven项目,并导入依赖pom.xml:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-webflux</artifactId>
    </dependency>
    <!-- data-r2dbc同时也会将r2dbc-pool导入 -->
    <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-r2dbc</artifactId>
    </dependency>
    <!-- r2dbc mysql 库-->
    <dependency>
    <groupId>dev.miku</groupId>
    <artifactId>r2dbc-mysql</artifactId>
    <scope>runtime</scope>
    </dependency>
    <dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <scope>runtime</scope>
    </dependency>
    <dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <optional>true</optional>
    </dependency>
  2. 配置文件application.yml

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    spring:
    r2dbc:
    url: r2dbcs:mysql://192.168.2.100:3306/test?characterEncoding=UTF8&serverTimezone=Asia/Shanghai
    username: developer
    password: 123456

    #日志配置
    logging:
    level:
    root: info
    # 调试环境查看执行的sql
    dev.miku.r2dbc.mysql.client.ReactorNettyClient: debug
  3. SQLModel

    1
    2
    3
    4
    5
    6
    7
    8
    9
    create table `base_user` (
    `userId` int not null auto_increment,
    `userName` varchar(100) default null comment '用户名',
    `userMobile` varchar(20) default null comment '手机号',
    primary key (`userId`),
    unique key `userMobile` (`userMobile`)
    ) engine=innodb comment='测试用户信息';
    insert into `base_user` (`userName`, `userMobile`) values ('黑子', '15914061216');
    insert into `base_user` (`userName`, `userMobile`) values ('大黄', '15914061217');
1
2
3
4
5
6
@Data
public class BaseUser {
private Integer id;
private String name;
private String mobile;
}

实际开发中,由于历史原因数据库字段大多与Model类字段无法对应,这里也不对应,在sql中用别名对应。

  1. 编写DAO层,这里继承的事响应式的crudReactiveCrudRepository

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    @Repository
    public interface BaseUserDao extends ReactiveCrudRepository<BaseUser, Integer> {
    /**
    * 根据用户id查询用户
    * @param id userId
    * @return BaseUser
    */
    @Override
    @Query("select userId as id, userMobile as mobile, userName as name from base_user where userId= :id")
    Mono<BaseUser> findById(Integer id);

    /**
    * 更新用户名
    * @param id userId
    * @param name userName
    */
    @Modifying
    @Query("update base_user set userName= :name where userId= :id")
    Mono<Integer> updateNameById(Integer id, String name);

    /**
    * 新增用户
    * @param name userName
    * @param mobile userMobile
    */
    @Modifying
    @Query("insert into base_user(userName, userMobile) values (:name, :mobile)")
    Mono<Void> insertUser(String name, String mobile);

    /**
    * 根据用户id删除用户
    * @param id userId
    */
    @Override
    @Modifying
    @Query("delete from base_user where userId= :id")
    Mono<Void> deleteById(Integer id);
    }
  2. 编写Service层,这里返回的值为Reactor的对象FluxMono

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    @Service
    @RequiredArgsConstructor
    public class BaseUserService {

    private final BaseUserDao baseUserDao;

    public Mono<BaseUser> findById (Integer id) {
    return baseUserDao.findById(id);
    }

    public Mono<Integer> updateById(BaseUser user){
    return baseUserDao.updateNameById(user.getId(), user.getName());
    }

    public Mono<Void> insertUser(BaseUser user){
    return baseUserDao.insertUser(user.getName(), user.getMobile());
    }

    public Mono<Void> deleteById(Integer id) {
    return baseUserDao.deleteById(id);
    }

    }
  3. 编写Controller

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    @RestController
    @RequiredArgsConstructor
    @RequestMapping("/user")
    public class TestApi {

    private final BaseUserService baseUserService;

    @GetMapping("/get")
    public Mono<BaseUser> findById(Integer id) {
    return baseUserService.findById(id);
    }

    @PostMapping("/update")
    public Mono<Integer> updateById(BaseUser user) {
    return baseUserService.updateById(user);
    }

    @PostMapping("/insert")
    public Mono<Void> insertUser(BaseUser user) {
    return baseUserService.insertUser(user);
    }

    @PostMapping("/delete")
    public Mono<Void> deleteById(Integer id) {
    return baseUserService.deleteById(id);
    }
    }
  4. 测试:

    • 查询:curl -X GET "http://localhost:8080/user/get?id=1"
    • 更新:curl -X POST "http://localhost:8080/user/update?id=1&name=小黑子"
    • 新增:curl -X POST "http://localhost:8080/user/insert?name=小蓝子&mobile=15815011618"
    • 删除:curl -X POST "http://localhost:8080/user/delete?id=1"

本文使用Spring Boot版本:2.4.3

文章目录