liujijiang

Spring反应式持久化数据

2020.03.22

目前还没有关系型数据库支持反应式编程
支持反应式编程的只有非关系数据库例如:Cassandra,MongoDB,Redis


关系型数据库

如果使用关系型数据库,你可以借助反应式和非反应式之间进行转换,使得上游组件从中受益

例如:

public void test(){
        
        List<User> userList = userRepository.findAll();

        Flux<User> userFlux = Flux.fromIterable(userList);

        User user = userRepository.findByUsernameAndOrderByIdAsc(username);
        
        Mono<User> userMono = Mono.just(user);
    }

非关系型数据库

MongoDB

MongoDB是一个知名的NoSQL数据库,MongoDB是文档数据库,以二进制JSON来存储文档

引入依赖

	<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-mongodb-reactive</artifactId>
        </dependency>

因为这里要用的是支持反应式的MOngoDB,所以引入的是mongodb-reactive
如果不用反应式的MongoDB,就不需要加reactive

如果在开发测试阶段也可以使用嵌入式的MongoDB

	<dependency>
            <groupId>de.flapdoodle.embed</groupId>
            <artifactId>de.flapdoodle.embed.mongo</artifactId>
        </dependency>

类似于嵌入式的H2数据库,所有的数据存储在内存中,我们不需要运行单独的数据库,但是一旦关机,所有数据丢失

配置application.yml

spring:
  data:
    mongodb:
      host: jjboy.vip
      port: 27017
      username: root
      password: 123456
      database: test
  • host:主机名
  • port:端口,默认为27017
  • username:用户名
  • password:密码
  • database:数据库名,默认为test

将领域对象映射为文档

使用到的几个注解:

  • @Id:将某个属性指明为ID
  • @Document:标注在类上,将类映射为数据库文档
  • @Field:属性持久化到数据库中时的字段名
package com.reactivemongo.reactive.document.model;

import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.RequiredArgsConstructor;
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;

import java.util.Collection;

/**
 * @ClassName User
 * @Description
 * @Auther liuxiansen
 * @Date 2020/3/22 9:04 上午
 **/
@Data
@NoArgsConstructor
@Document(collection = "users")
public class User implements UserDetails {

    @Id
    private String id;

    private String username;

    private String password;

    private String email;

    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        return null;
    }

    @Override
    public boolean isAccountNonExpired() {
        return true;
    }

    @Override
    public boolean isAccountNonLocked() {
        return true;
    }

    @Override
    public boolean isCredentialsNonExpired() {
        return true;
    }

    @Override
    public boolean isEnabled() {
        return true;
    }
}

id可以为任意的Serializable类型上,当为String时,MongoDB会自动为其赋值

编写反应式的Repository接口

有两个可以接口供我们选择

  • ReactiveCrudRepository
  • ReactiveMongoRepository
    区别:ReactiveMongoRepository是ReactiveCrudRepository的优化,前者对ReactiveCrudRepository进行了优化,而且只能使用在MongoDB上,而后者还可以使用在其他的数据库上,如果你的项目日后不需要更换数据库,那么你就完全可以使用前者
package com.reactivemongo.reactive.repository;

import com.reactivemongo.reactive.document.model.User;
import org.springframework.data.mongodb.repository.ReactiveMongoRepository;
import org.springframework.web.bind.annotation.CrossOrigin;
import reactor.core.publisher.Flux;

/**
 * @ClassName UserRepository
 * @Description
 * @Auther liuxiansen
 * @Date 2020/3/22 9:07 上午
 **/
@CrossOrigin
public interface UserRepository extends ReactiveMongoRepository<User,String> {

    Flux<User> findByUsernameAndOrderByIdAsc(String username);
}


在反应式数据库的操作中,我们其实可以不用分页查找
我们可以使用反应流的 take() 方法从中取出最大多少个
可以使用OrderBy 来进行排序