WebFlux/r2dbc/mysql增删改查Demo
环境和版本
jdk1.8
springboot 2.7.6
idea
依赖
pom.xml
部分内容:
<properties>
<java.version>1.8</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<spring-boot.version>2.7.6</spring-boot.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-r2dbc</artifactId>
</dependency>
<dependency>
<groupId>io.asyncer</groupId>
<artifactId>r2dbc-mysql</artifactId>
<version>1.3.0</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</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>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring-boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
配置
application.yml
spring:
r2dbc:
url: r2dbc:mysql://localhost:3306/r2dbc_demo?useServerPrepareStatement=true&useClientPrepareStatement=true&sslMode=DISABLED&serverZoneId=Asia/Shanghai
username: root
password: qk123
pool:
enabled: true
initial-size: 1
validation-query: select 1
sql:
init:
mode: always
logging:
level:
com.example.demo.three: debug
server:
port: 8080
模仿MybtisPlus的BaseMapper和Service
BaseRepository,java
package com.example.demo.three.base.repository;
import org.springframework.data.r2dbc.repository.R2dbcRepository;
import org.springframework.data.repository.reactive.ReactiveCrudRepository;
public interface BaseRepository<T, ID> extends ReactiveCrudRepository<T, ID>, R2dbcRepository<T, ID> {
}
IService.java
package com.example.demo.three.base.service;
import com.example.demo.three.base.repository.BaseRepository;
import reactor.core.publisher.Mono;
@SuppressWarnings("unchecked")
public interface IService<T, ID> {
/**
* 默认批次提交数量
*/
int DEFAULT_BATCH_SIZE = 1000;
/**
* 插入一条记录(选择字段,策略插入)
*
* @param entity 实体对象
*/
default Mono<T> save(T entity) {
return getBaseRepository().save(entity);
}
/**
* 根据 ID 删除
*
* @param id 主键ID
*/
default Mono<Void> removeById(ID id) {
return getBaseRepository().deleteById(id);
}
/**
* 根据 ID 选择修改
*
* @param entity 实体对象
*/
default Mono<T> updateById(T entity) {
return getBaseRepository().save(entity);
}
default Mono<T> getById(ID id) {
return getBaseRepository().findById(id);
}
BaseRepository<T, ID> getBaseRepository();
}
ServiceImpl.java
package com.example.demo.three.base.service.impl;
import com.example.demo.three.base.repository.BaseRepository;
import com.example.demo.three.base.service.IService;
import lombok.extern.slf4j.Slf4j;
import javax.annotation.Resource;
@Slf4j
public class ServiceImpl<R extends BaseRepository<T, ID>, T, ID> implements IService<T, ID> {
@Resource
private R baseRepository;
@Override
public BaseRepository<T, ID> getBaseRepository() {
return baseRepository;
}
}
配置扫描RepositoryRepositoryConfig .java
package com.example.demo.three.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.r2dbc.repository.config.EnableR2dbcRepositories;
@Configuration
@EnableR2dbcRepositories("com.example.demo.three.repository")
public class RepositoryConfig {
}
创建一个实体类User.java
package com.example.demo.three.entity;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.experimental.Accessors;
import org.springframework.data.annotation.Id;
import org.springframework.data.relational.core.mapping.Column;
import org.springframework.data.relational.core.mapping.Table;
@Getter
@Setter
@Accessors(chain = true)
@AllArgsConstructor
@NoArgsConstructor
@Table("t_user")
public class User {
@Id
private Long id;
@Column("name")
private String name;
@Column("username")
private String username;
@Column("password")
private String password;
}
以及它的Repository
、Service
、Controller
UserRepository.java
package com.example.demo.three.repository;
import com.example.demo.three.base.repository.BaseRepository;
import com.example.demo.three.entity.User;
import org.springframework.stereotype.Repository;
@Repository
public interface UserRepository extends BaseRepository<User, Long> {
}
UserService.java
package com.example.demo.three.service;
import com.example.demo.three.base.service.IService;
import com.example.demo.three.entity.User;
public interface UserService extends IService<User, Long> {
}
UserServiceImpl.java
package com.example.demo.three.service;
import com.example.demo.three.base.service.impl.ServiceImpl;
import com.example.demo.three.entity.User;
import com.example.demo.three.repository.UserRepository;
import org.springframework.stereotype.Service;
@Service
public class UserServiceImpl extends ServiceImpl<UserRepository, User, Long> implements UserService{
}
再加上接口UserController.java
package com.example.demo.three.controller;
import com.example.demo.three.entity.User;
import com.example.demo.three.service.UserService;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Mono;
import javax.annotation.Resource;
@RestController
@RequestMapping("/user")
public class UserController {
@Resource
private UserService userService;
/**
* 新增用户
* @param user 用户请求信息
* @return 用户新增后信息
*/
@PostMapping("/add")
public Mono<User> add(@RequestBody User user){
return userService.save(user);
}
/**
* 根据id删除用户
* @param id 用户id
* @return 无
*/
@DeleteMapping("/delete/{id}")
public Mono<Void> deleteById(@PathVariable("id") Long id) {
return userService.removeById(id);
}
/**
* 根据id更新用户
* @param user 用户信息
* @return 新用户信息
*/
@PutMapping("/update")
public Mono<User> update(@RequestBody User user) {
return userService.updateById(user);
}
/**
* 根据id查询用户
* @param id 用户id
* @return 用户信息
*/
@GetMapping("/get/{id}")
public Mono<User> getById(@PathVariable("id") Long id) {
return userService.getById(id);
}
}
验证
启动服务,后调用新增接口。
新增成功,但是修改和删除都会报错。这个报错是提交事务之后报的,也就是会更改数据库。
经过定位,发现最终调用R2dbcEntityTemplate.doDelete
方法,返回的是Mono<Integer>
,但是驱动返回的是Long
,导致不兼容。
有两个方法解决。
方法一:
升级jdk
到17
以上
方法二:
更换MySql
驱动库
<dependency>
<groupId>dev.miku</groupId>
<artifactId>r2dbc-mysql</artifactId>
<version>0.8.2.RELEASE</version>
</dependency>
<!-- 用这个驱动删除和修改会报类型转换异常 -->
<!-- <dependency>-->
<!-- <groupId>io.asyncer</groupId>-->
<!-- <artifactId>r2dbc-mysql</artifactId>-->
<!-- <version>1.3.0</version>-->
<!-- </dependency>-->