Spring WebFlux和Spring Data R2DBC是Spring Framework生态系统中的两个重要组件,用于构建响应式应用程序和与关系型数据库交互。
-
Spring WebFlux: Spring WebFlux是Spring Framework 5中引入的响应式编程框架。与传统的Servlet API不同,Spring WebFlux提供了一种基于反应式流的方式来处理Web请求和响应。它支持异步和非阻塞的IO操作,使得应用程序能够更有效地处理高并发的情况。
特点:
- 响应式:使用反应式流处理请求和响应,支持异步和非阻塞的IO操作。
- 高性能:能够处理高并发的情况,提供了高效的事件驱动模型。
- 弹性:能够轻松地处理流量激增和负载均衡。
-
Spring Data R2DBC: Spring Data R2DBC是Spring Data项目的一部分,专门用于与关系型数据库进行交互。与传统的Spring Data JPA不同,Spring Data R2DBC支持异步和非阻塞的数据库访问,与Spring WebFlux完美契合,从而构建全栈响应式应用程序。
特点:
- 非阻塞:基于Reactive Streams标准实现,支持异步和非阻塞的数据库访问。
- 异步API:提供了异步的Repository API,允许在响应式流中处理数据库操作。
- 响应式编程:与Spring WebFlux等响应式框架集成,支持响应式编程模型。
- 支持的数据库:支持使用R2DBC(Reactive Relational Database Connectivity)规范的关系型数据库,如PostgreSQL、MySQL等。
综上所述,Spring WebFlux和Spring Data R2DBC为构建响应式应用程序提供了强大的支持,使开发人员能够利用异步和非阻塞的编程模型构建高性能、弹性的应用程序,并与关系型数据库进行高效交互。
注意:启动类需要添加该注解,指定存放Repository类的目录
@EnableR2dbcRepositories(basePackages = "com.test.service.postgres")
1、引用Maven依赖
<!-- webflux reactive -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
<version>2.7.9</version>
</dependency>
<!-- r2db -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-r2dbc</artifactId>
<version>2.7.9</version>
</dependency>
<!-- postgresql -->
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>r2dbc-postgresql</artifactId>
</dependency>
2、YAML配置
spring:
r2dbc:
url: r2dbc:postgresql://localhost:5432/database_name
username: your_username
password: your_password
pool:
initialSize: 10
maxSize: 20
maxIdleTime: 30m
validationQuery: "SELECT 1"
connectionTimeout: 10s
maxLifeTime: 10m
3、用户表
/**
* @author Lucas
* date 2024/2/15 18:46
* description 用户表
*/
@Data
@Table(name = "sys_user")
public class User implements Persistable<String> {
@Id
private String id;
/**
* 姓名
*/
private String name;
/**
* 年龄
*/
private Integer age;
@Transient
private boolean isNew;
@Override
@Transient
public boolean isNew() {
return this.isNew || id == null;
}
public User setAsNew(){
this.isNew = true;
return this;
}
}
4、用户表Repository
/**
* @author Lucas
* date 2024/2/15 19:39
* description 用户表Repository
*/
@Repository
public interface UserRepository extends R2dbcRepository<User, String> {
/**
* 判断是否存在
* @param name
* @return
*/
Mono<Integer> countByName(String name);
/**
* 修改
* @param Id
* @param name
* @param age
* @return
*/
@Modifying/*查询不需要加该注解*/
@Query("update sys_user set name = :name,age = :age where id = :Id")
Mono<Boolean> updateUser(String Id, String name, Integer age);
/**
* 获取该年龄所有用户
* @param age
* @return
*/
Flux<User> findByAge(Integer age);
}
5、用户ServiceImpl
/**
* @author Lucas
* date 2024/2/15 19:48
* description 用户ServiceImpl
*/
@Slf4j
@Service
@RequiredArgsConstructor
public class UserServiceImpl implements UserService {
private final UserRepository userRepository;
@Override
public Mono<Boolean> saveUser(User user) {
return userRepository.countByName(user.getName()).flatMap(i -> {
if (i > 0) {
return Mono.error(new Exception("该用户名已存在,请勿重复创建"));
}
//setAsNew()的作用主要是自己生成主键ID执行新增,不然传ID会执行修改操作报错ID不存在,自增ID不需要该方法
return userRepository.save(user.setAsNew()).map(r -> true);
});
}
@Override
public Mono<Boolean> updateUser(User user) {
return userRepository.updateUser(user.getId(), user.getName(), user.getAge());
}
@Override
public Mono<List<User>> getUserList(Integer age) {
return userRepository.findByAge(age).collectList();
}
}
6、用户Service
/**
* @author Lucas
* date 2024/2/15 19:47
* description 用户Service
*/
public interface UserService {
/**
* 新增用户
* @param user
* @return
*/
Mono<Boolean> saveUser(User user);
/**
* 修改用户
* @param user
* @return
*/
Mono<Boolean> updateUser(User user);
/**
* 获取指定年龄所有用户
* @param age
* @return
*/
Mono<List<User>> getUserList(Integer age);
}
7、用户Controller
/**
* @author Lucas
* date 2024/2/12 18:07
* description 用户Controller
*/
@Slf4j
@RestController
@RequestMapping("/user")
@RequiredArgsConstructor
public class UserController {
private final UserService userService;
/**
* 新增用户
* @param user
* @return
*/
@RequestMapping(value = "/saveUser", method = RequestMethod.POST, headers = {"X-HTTP-Method-Override=POST"})
public Mono<Boolean> saveUser(@RequestBody @Validated User user) {
return userService.saveUser(user);
}
/**
* 修改用户
* @param user
* @return
*/
@RequestMapping(value = "/updateUser", method = RequestMethod.POST, headers = {"X-HTTP-Method-Override=POST"})
public Mono<Boolean> updateUser(@RequestBody @Validated User user) {
return userService.updateUser(user);
}
/**
* 获取指定年龄所有用户
* @param age
* @return
*/
@RequestMapping(value = "/getUserList", method = RequestMethod.POST, headers = {"X-HTTP-Method-Override=GET"})
public Mono<List<User>> getUserList(@RequestParam @NotNull Integer age) {
return userService.getUserList(age);
}
}