dbc连接mysql_Spring WebFlux 使用 R2DBC 访问 MySQL
一、介紹
Reactive Programming
響應(yīng)式編程指的是數(shù)據(jù)驅(qū)動(dòng)的、異步和并發(fā)的編程范式。簡(jiǎn)而言之,異步數(shù)據(jù)流編程。對(duì)于數(shù)據(jù)流進(jìn)行創(chuàng)建、組合、過濾、轉(zhuǎn)換等操作,最終得到所需要的處理和結(jié)果。典型的框架有 RxJava、Reactor 等。
WebFlux
WebFlux 是 Spring Framework 提供的新一代 Web 開發(fā)框架,區(qū)別于 Spring MVC,WebFlux 提供了非阻塞的、基于 Reactive 技術(shù)棧的開發(fā)框架,以發(fā)揮出多核編程的優(yōu)勢(shì)。
兩者的異同如下:
WebFlux.jpeg
MySQL 支持
直到 Spring Boot 2.3.0.RELEASE,才正式支持基于 r2dbc 的 MySQL 驅(qū)動(dòng)。
本文使用的框架、環(huán)境和工具如下:
二、創(chuàng)建工程
本文基于 IntelliJ IDEA 來創(chuàng)建工程,讀者也可以自行基于 spring initializr 來創(chuàng)建。
1. 新建工程
點(diǎn)擊菜單中【File】→【New】→ 【Project...】,出現(xiàn)以下對(duì)話框,選擇 Spring initializr:
1.png
說明
JDK: 選擇 JDK 8 及以上,建議使用 OpenJDK,以避免法律風(fēng)險(xiǎn)
從 2020.1 開始, IntelliJ IDEA 已經(jīng)自帶有 JDK 下載功能,不需要再獨(dú)立下載和安裝
在 Project SDK 欄中下拉,選擇 Download JDK...,出現(xiàn)下面的對(duì)話框,選擇合適的版本下載即可。
2.png
2. 填寫項(xiàng)目信息
點(diǎn)擊 Next,進(jìn)入填寫項(xiàng)目信息界面。
3.png
說明
Group 和 Artifact:根據(jù)需要修改
Type:保持 Maven Project
3. 選擇特性
點(diǎn)擊 Next,進(jìn)入選擇特性界面。
4.png
說明
選擇以下組件:
Developer Tools
Lombok
Web
Spring Reactive Web
SQL
Spring Data R2DBC
MySQL Driver
4. 設(shè)置項(xiàng)目名稱和目錄界面
點(diǎn)擊 Next,進(jìn)入設(shè)置項(xiàng)目名稱和目錄界面,保持默認(rèn)即可。
5.png
5. 生成項(xiàng)目
點(diǎn)擊 Finish,生成項(xiàng)目,進(jìn)入 IDE,典型的 Spring Boot 項(xiàng)目結(jié)構(gòu)。
6.png
三、準(zhǔn)備 MySQL 數(shù)據(jù)
在開始寫代碼之前,先準(zhǔn)備好測(cè)試用的數(shù)據(jù)環(huán)境。本文使用的是 MySQL 8.0.19。MySQL 社區(qū)版的官方下載地址是 MySQL Community Server。
安裝 MySQL
如果有現(xiàn)成的 MySQL 環(huán)境,請(qǐng)?zhí)^此步驟。
Windows 用戶:直接下載 MySQL Installer for Windows,安裝即可。
Mac 用戶: 使用 homebrew 安裝更為便捷,命令如下:
brew install mysql
創(chuàng)建 database
首先,創(chuàng)建 database spring_r2dbc_samples,并創(chuàng)建用戶 spring_r2dbc_samples_user,腳本如下:
CREATE DATABASE `spring_r2dbc_samples` CHARACTER SET 'utf8mb4' COLLATE 'utf8mb4_general_ci';
CREATE USER `spring_r2dbc_samples_user`@`%` IDENTIFIED WITH mysql_native_password BY 'B55!3Ufhj';
CREATE USER `spring_r2dbc_samples_user`@`localhost` IDENTIFIED WITH mysql_native_password BY 'B55!3Ufhj';
GRANT all privileges ON `spring_r2dbc_samples`.* TO `spring_r2dbc_samples_user`@`%`;
GRANT all privileges ON `spring_r2dbc_samples`.* TO `spring_r2dbc_samples_user`@`localhost`;
flush privileges;
創(chuàng)建表
本文所使用的表的 ER 圖如下:
7.png
基礎(chǔ)字段
字段代碼
字段名稱
說明
id
編號(hào)
主鍵,自增
remark
備注
可選
active
有效標(biāo)志
缺省為 1
createdAt
創(chuàng)建時(shí)間
默認(rèn)為 CURRENT_TIMESTAMP
createdBy
創(chuàng)建人
updatedAt
更新時(shí)間
默認(rèn)為 CURRENT_TIMESTAMP,記錄更新時(shí)自動(dòng)更新
updatedBy
更新人
學(xué)生表
除了基礎(chǔ)字段,還包含以下主要字段:
字段代碼
字段名稱
說明
code
學(xué)號(hào)
name
姓名
gender
性別
M: 男 F: 女
birthday
生日
address
家庭地址
表創(chuàng)建腳本
ALTER TABLE `spring_r2dbc_samples`.`Student` DROP INDEX `idx_main`;
DROP TABLE `spring_r2dbc_samples`.`Student`;
CREATE TABLE `spring_r2dbc_samples`.`Student` (
`id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT,
`code` varchar(50) NOT NULL,
`name` varchar(50) NOT NULL,
`gender` char(1) NOT NULL,
`birthday` date NOT NULL,
`address` varchar(300) NULL,
`remark` varchar(1000) NULL,
`active` tinyint NOT NULL DEFAULT 1,
`createdAt` datetime(0) NOT NULL DEFAULT CURRENT_TIMESTAMP(0),
`createdBy` varchar(50) NOT NULL,
`updatedAt` datetime(0) NOT NULL DEFAULT CURRENT_TIMESTAMP(0) ON UPDATE CURRENT_TIMESTAMP(0),
`updatedBy` varchar(50) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE INDEX `idx_main`(`code`)
);
準(zhǔn)備測(cè)試數(shù)據(jù)
-- Student
delete from Student;
insert into Student(code, name, gender, birthday, address, createdBy, updatedBy)
values
('S0001', 'Tom', 'M', '2001-03-05', null, 'TEST', 'TEST')
, ('S0002', 'Ted', 'M', '2001-06-12', null, 'TEST', 'TEST')
, ('S0003', 'Mary', 'F', '2001--9-12', 'Chicago', 'TEST', 'TEST')
;
四、訪問數(shù)據(jù)
配置數(shù)據(jù)源
首選,把 /src/main/resources/application.properties 改名為 application.yml,即 YAML 格式。這個(gè)純屬個(gè)人喜好,覺得配置起來結(jié)構(gòu)更清晰點(diǎn)。YAML 早先是隨著 Ruby 和 Ruby on Rails 的流行而流行起來的,簡(jiǎn)單直接,比起 json 少了括號(hào)和雙引號(hào),作為配置文件,還是非常不錯(cuò)的。
修改配置文件 application.yml,加入以下配置:
spring:
r2dbc:
url: r2dbcs:mysql://localhost:3306/spring_r2dbc_samples?sslMode=DISABLED
username: spring_r2dbc_samples_user
password: B55!3Ufhj
創(chuàng)建實(shí)體類
創(chuàng)建子 package entity
創(chuàng)建實(shí)體類 Student
使用 Lombok 的 @Data 來使得 Student 類可訪問
@ReadOnlyProperty 的作用是防止代碼修改創(chuàng)建時(shí)間和更新時(shí)間,這個(gè)會(huì)由 MySQL 自動(dòng)完成
目前 R2DBC 尚不支持 Audit 功能,所以 createdBy 和 updatedBy 還不能自動(dòng)設(shè)置
代碼如下:
package com.example.webfluxmysqldemo.entity;
import lombok.Data;
import org.springframework.data.annotation.Id;
import org.springframework.data.annotation.ReadOnlyProperty;
import java.time.LocalDate;
import java.time.LocalDateTime;
@Data
public class Student {
@Id
private Long id;
private String code;
private String name;
private String gender;
private LocalDate birthday;
private String address;
private String remark;
private boolean active;
@ReadOnlyProperty
private LocalDateTime createdAt;
private String createdBy;
@ReadOnlyProperty
private LocalDateTime updatedAt;
private String updatedBy;
}
創(chuàng)建倉庫類
倉庫(repository) 類似于原先的 dao 的角色,主要提供各種底層數(shù)據(jù)訪問功能。Spring Data JPA 中首選推出了 repository 的概念, Spring Data R2DBC 也基本沿用,但是功能上沒有 JPA 那么強(qiáng)大。
創(chuàng)建子 package repository
創(chuàng)建倉庫類 StudentRepository,繼承自 ReactiveCrudRepository
代碼如下:
package com.example.webfluxmysqldemo.repository;
import com.example.webfluxmysqldemo.entity.Student;
import org.springframework.data.repository.reactive.ReactiveCrudRepository;
public interface StudentRepository extends ReactiveCrudRepository {
}
創(chuàng)建控制器
創(chuàng)建子 package controller
創(chuàng)建控制器 StudentController,并映射到 /api/students
注入 StudentRepository
創(chuàng)建方法,獲取所有學(xué)生
代碼如下:
package com.example.webfluxmysqldemo.controller;
import com.example.webfluxmysqldemo.entity.Student;
import com.example.webfluxmysqldemo.repository.StudentRepository;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Flux;
@RestController
@RequestMapping("/api/students")
public class StudentController {
private final StudentRepository studentRepository;
public StudentController(StudentRepository studentRepository) {
this.studentRepository = studentRepository;
}
@GetMapping("")
public Flux index() {
return studentRepository.findAll();
}
}
編譯和啟動(dòng)
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v2.3.0.RELEASE)
2020-06-07 16:22:27.000 INFO 65817 --- [ main] c.e.w.WebfluxMysqlDemoApplication : Starting WebfluxMysqlDemoApplication on Arthur-MacBook-Pro.local with PID 65817 (/Users/arthur/github/arthurlee/webflux-mysql-demo/target/classes started by arthur in /Users/arthur/github/arthurlee/webflux-mysql-demo)
2020-06-07 16:22:27.002 INFO 65817 --- [ main] c.e.w.WebfluxMysqlDemoApplication : No active profile set, falling back to default profiles: default
2020-06-07 16:22:27.648 INFO 65817 --- [ main] .s.d.r.c.RepositoryConfigurationDelegate : Bootstrapping Spring Data R2DBC repositories in DEFAULT mode.
2020-06-07 16:22:27.737 INFO 65817 --- [ main] .s.d.r.c.RepositoryConfigurationDelegate : Finished Spring Data repository scanning in 82ms. Found 1 R2DBC repository interfaces.
2020-06-07 16:22:28.692 INFO 65817 --- [ main] o.s.b.web.embedded.netty.NettyWebServer : Netty started on port(s): 8080
2020-06-07 16:22:28.701 INFO 65817 --- [ main] c.e.w.WebfluxMysqlDemoApplication : Started WebfluxMysqlDemoApplication in 2.167 seconds (JVM running for 2.934)
訪問數(shù)據(jù)
[
{
"id": 4,
"code": "S0001",
"name": "Tom",
"gender": "M",
"birthday": "2001-03-05",
"address": null,
"remark": null,
"active": true,
"createdAt": null,
"createdBy": null,
"updatedAt": null,
"updatedBy": null
},
{
"id": 5,
"code": "S0002",
"name": "Ted",
"gender": "M",
"birthday": "2001-06-12",
"address": null,
"remark": null,
"active": true,
"createdAt": null,
"createdBy": null,
"updatedAt": null,
"updatedBy": null
},
{
"id": 6,
"code": "S0003",
"name": "Mary",
"gender": "F",
"birthday": "2001-09-12",
"address": "Chicago",
"remark": null,
"active": true,
"createdAt": null,
"createdBy": null,
"updatedAt": null,
"updatedBy": null
}
]
出現(xiàn)問題
查詢資料后,發(fā)現(xiàn)缺省情況下,createAt 會(huì)轉(zhuǎn)換成數(shù)據(jù)庫字段 created_at,所以沒有成功映射。
解決問題
定位問題后,可以添加一個(gè)配置,自定義命名轉(zhuǎn)換規(guī)則。
創(chuàng)建子 package config
添加配置類 R2dbcConfig (名稱隨意)
添加 Bean,返回 NamingStrategy
代碼如下:
package com.example.webfluxmysqldemo.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.relational.core.mapping.NamingStrategy;
import org.springframework.data.relational.core.mapping.RelationalPersistentProperty;
@Configuration
public class R2dbcConfig {
@Bean
public NamingStrategy namingStrategy() {
return new NamingStrategy() {
@Override
public String getColumnName(RelationalPersistentProperty property) {
return property.getName();
}
};
}
}
重新運(yùn)行和驗(yàn)證
重新運(yùn)行,訪問接口,得到數(shù)據(jù)如下,問題解決!
[
{
"id": 4,
"code": "S0001",
"name": "Tom",
"gender": "M",
"birthday": "2001-03-05",
"address": null,
"remark": null,
"active": true,
"createdAt": "2020-06-07T15:47:07",
"createdBy": "TEST",
"updatedAt": "2020-06-07T15:47:07",
"updatedBy": "TEST"
},
{
"id": 5,
"code": "S0002",
"name": "Ted",
"gender": "M",
"birthday": "2001-06-12",
"address": null,
"remark": null,
"active": true,
"createdAt": "2020-06-07T15:47:07",
"createdBy": "TEST",
"updatedAt": "2020-06-07T15:47:07",
"updatedBy": "TEST"
},
{
"id": 6,
"code": "S0003",
"name": "Mary",
"gender": "F",
"birthday": "2001-09-12",
"address": "Chicago",
"remark": null,
"active": true,
"createdAt": "2020-06-07T15:47:07",
"createdBy": "TEST",
"updatedAt": "2020-06-07T15:47:07",
"updatedBy": "TEST"
}
]
五、參考
后續(xù)
本文引領(lǐng)大家進(jìn)入 R2DBC的世界,搭建出了一個(gè)可運(yùn)行的最小項(xiàng)目,后續(xù)將著重介紹 R2DBC 提供的各種功能。
總結(jié)
以上是生活随笔為你收集整理的dbc连接mysql_Spring WebFlux 使用 R2DBC 访问 MySQL的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【天意使用教程系列】破解系统登录密码
- 下一篇: hive metastore mysql