WebFlux 整合 Mongodb

前言

上一讲用 Map 数据结构内存式存储了数据。这样数据就不会持久化,本文我们用 MongoDB 来实现 WebFlux 对数据源的操作。

什么是 MongoDB ?

官网:https://www.mongodb.com/

MongoDB 是一个基于分布式文件存储的数据库,由 C++ 语言编写,旨在为 WEB 应用提供可扩展的高性能数据存储解决方案。

MongoDB 是一个介于关系数据库和非关系数据库之间的产品,是非关系数据库当中功能最丰富,最像关系数据库的。

由于操作方便,本文用 Docker 启动一个 MognoDB 服务。如果 Docker 不会安装的,请参考此文:Docker 安装与基本操作 https://www.jianshu.com/p/f272726db9c5

Docker 安装 MognoDB 并启动如下:

1、创建挂载目录

  1. docker volume create mongo_data_db
  2. docker volume create mongo_data_configdb

2、启动 MognoDB

  1. docker run -d \
  2. --name mongo \
  3. -v mongo_data_configdb:/data/configdb \
  4. -v mongo_data_db:/data/db \
  5. -p 27017:27017 \
  6. mongo \
  7. --auth

3、初始化管理员账号

  1. docker exec -it mongo mongo admin
  2. // 容器名 // mongo命令 数据库名
  3. # 创建最高权限用户
  4. db.createUser({ user: 'admin', pwd: 'admin', roles: [ { role: "root", db: "admin" } ] });

4、测试连通性

  1. docker run -it --rm --link mongo:mongo mongo mongo -u admin -p admin --authenticationDatabase admin mongo/admin

MognoDB 基本操作:

类似 MySQL 命令,显示库列表:

  1. show dbs

使用某数据库

  1. use admin

显示表列表

  1. show collections

如果存在 city 表,格式化显示 city 表内容

  1. db.city.find().pretty()

结构

类似上面讲的工程搭建,新建一个工程编写此案例。工程如图:

目录核心如下

  • pom.xml maven 配置
  • application.properties 配置文件
  • dao 数据访问层,本文要点

新增 POM 依赖与配置

在 pom.xml 配置新的依赖:

  1. <!-- Spring Boot 响应式 MongoDB 依赖 -->
  2. <dependency>
  3. <groupId>org.springframework.boot</groupId>
  4. <artifactId>spring-boot-starter-data-mongodb-reactive</artifactId>
  5. </dependency>

类似配了 MySQL 和 JDBC 驱动,肯定得去配置数据库。在 application.properties 配置下上面启动的 MongoDB 配置:

数据库名为 admin、账号密码也为 admin。

  1. spring.data.mongodb.host=localhost
  2. spring.data.mongodb.database=admin
  3. spring.data.mongodb.port=27017
  4. spring.data.mongodb.username=admin
  5. spring.data.mongodb.password=admin

这就一个巨大的问题了,为啥不用我们常用的 MySQL 数据库呢?

答案是 Spring Data Reactive Repositories 目前支持 Mongo、Cassandra、Redis、Couchbase。不支持 MySQL ,那究竟为啥呢?那就说明下 JDBC 和 Spring Data 的关系。

Spring Data Reactive Repositories 突出点是 Reactive,即非阻塞的。区别如下:

  • 基于 JDBC 实现的 Spring Data ,比如 Spring Data JPA 是阻塞的。原理是基于阻塞 IO 模型

    消耗每个调用数据库的线程(Connection)
  • 事务只能在一个 java.sql.Connection 使用,即一个事务一个操作。

那如何异步非阻塞封装下 JDBC 的思想也不新鲜,Scala 库 Slick 3 就实现了。简单的实现原理如下:

  • 一个事务多个操作,那么共享一个 java.sql.Connection 。可以使用透明事务管理,利用回调编程模型去传递
  • 保持有限的空闲连接

最后,我坚信非阻塞 JDBC 很快就会出现的。这样我们就开心的调用 MySQL 了。

对象

修改 org.spring.springboot.domain 包里面的城市实体对象类。修改城市(City)对象 City,代码如下:

  1. import org.springframework.data.annotation.Id;
  2. /**
  3. * 城市实体类
  4. *
  5. */
  6. public class City {
  7. /**
  8. * 城市编号
  9. */
  10. @Id
  11. private Long id;
  12. /**
  13. * 省份编号
  14. */
  15. private Long provinceId;
  16. /**
  17. * 城市名称
  18. */
  19. private String cityName;
  20. /**
  21. * 描述
  22. */
  23. private String description;
  24. public Long getId() {
  25. return id;
  26. }
  27. public void setId(Long id) {
  28. this.id = id;
  29. }
  30. public Long getProvinceId() {
  31. return provinceId;
  32. }
  33. public void setProvinceId(Long provinceId) {
  34. this.provinceId = provinceId;
  35. }
  36. public String getCityName() {
  37. return cityName;
  38. }
  39. public void setCityName(String cityName) {
  40. this.cityName = cityName;
  41. }
  42. public String getDescription() {
  43. return description;
  44. }
  45. public void setDescription(String description) {
  46. this.description = description;
  47. }
  48. }

@Id 注解标记对应库表的主键或者唯一标识符。因为这个是我们的 DO ,数据访问对象一一映射到数据存储。

MongoDB 数据访问层 CityRepository

修改 CityRepository 类,代码如下:

  1. import org.spring.springboot.domain.City;
  2. import org.springframework.data.mongodb.repository.ReactiveMongoRepository;
  3. import org.springframework.stereotype.Repository;
  4. @Repository
  5. public interface CityRepository extends ReactiveMongoRepository<City, Long> {
  6. }

CityRepository 接口只要继承 ReactiveMongoRepository 类即可。默认会提供很多实现,比如 CRUD 和列表查询参数相关的实现。ReactiveMongoRepository 接口默认实现了如下:

  1. <S extends T> Mono<S> insert(S var1);
  2. <S extends T> Flux<S> insert(Iterable<S> var1);
  3. <S extends T> Flux<S> insert(Publisher<S> var1);
  4. <S extends T> Flux<S> findAll(Example<S> var1);
  5. <S extends T> Flux<S> findAll(Example<S> var1, Sort var2);

如图,ReactiveMongoRepository 的集成类 ReactiveSortingRepository、ReactiveCrudRepository 实现了很多常用的接口:

ReactiveCrudRepository 接口如图所示:

另外可以看出,接口的命名是遵循规范的。常用命名规则如下:

  • 关键字 :: 方法命名
  • And :: findByNameAndPwd
  • Or :: findByNameOrSex
  • Is :: findById
  • Between :: findByIdBetween
  • Like :: findByNameLike
  • NotLike :: findByNameNotLike
  • OrderBy :: findByIdOrderByXDesc
  • Not :: findByNameNot

常用案例,代码如下:

  1. Flux<Person> findByLastname(String lastname);
  2. @Query("{ 'firstname': ?0, 'lastname': ?1}")
  3. Mono<Person> findByFirstnameAndLastname(String firstname, String lastname);
  4. // Accept parameter inside a reactive type for deferred execution
  5. Flux<Person> findByLastname(Mono<String> lastname);
  6. Mono<Person> findByFirstnameAndLastname(Mono<String> firstname, String lastname);
  7. @Tailable // Use a tailable cursor
  8. Flux<Person> findWithTailableCursorBy();

源码层面

ReactiveCrudRepository 抽象在 reactive 包,如图:

这里我们可以看出,支持了 reactive 还支持了 RxJava。对应老的 CrudRepository 新增了 ReactiveCrudRepository 接口及各种存储实现。

处理器类 Handler 和控制器类 Controller

修改下 Handler ,代码如下:

  1. @Component
  2. public class CityHandler {
  3. private final CityRepository cityRepository;
  4. @Autowired
  5. public CityHandler(CityRepository cityRepository) {
  6. this.cityRepository = cityRepository;
  7. }
  8. public Mono<City> save(City city) {
  9. return cityRepository.save(city);
  10. }
  11. public Mono<City> findCityById(Long id) {
  12. return cityRepository.findById(id);
  13. }
  14. public Flux<City> findAllCity() {
  15. return cityRepository.findAll();
  16. }
  17. public Mono<City> modifyCity(City city) {
  18. return cityRepository.save(city);
  19. }
  20. public Mono<Long> deleteCity(Long id) {
  21. cityRepository.deleteById(id);
  22. return Mono.create(cityMonoSink -> cityMonoSink.success(id));
  23. }
  24. }

不要对 Mono 、Flux 陌生,把他当成对象即可。继续修改下控制器类 Controller ,代码如下:

  1. @RestController
  2. @RequestMapping(value = "/city")
  3. public class CityWebFluxController {
  4. @Autowired
  5. private CityHandler cityHandler;
  6. @GetMapping(value = "/{id}")
  7. public Mono<City> findCityById(@PathVariable("id") Long id) {
  8. return cityHandler.findCityById(id);
  9. }
  10. @GetMapping()
  11. public Flux<City> findAllCity() {
  12. return cityHandler.findAllCity();
  13. }
  14. @PostMapping()
  15. public Mono<City> saveCity(@RequestBody City city) {
  16. return cityHandler.save(city);
  17. }
  18. @PutMapping()
  19. public Mono<City> modifyCity(@RequestBody City city) {
  20. return cityHandler.modifyCity(city);
  21. }
  22. @DeleteMapping(value = "/{id}")
  23. public Mono<Long> deleteCity(@PathVariable("id") Long id) {
  24. return cityHandler.deleteCity(id);
  25. }
  26. }

运行工程

一个 CRUD 的 Spring Boot Webflux 工程就开发完毕了,下面运行工程验证下。使用 IDEA 右侧工具栏,点击 Maven Project Tab ,点击使用下 Maven 插件的 install 命令。或者使用命令行的形式,在工程根目录下,执行 Maven 清理和安装工程的指令:

  1. cd springboot-webflux-3-mongodb
  2. mvn clean install

在控制台中看到成功的输出:

  1. ... 省略
  2. [INFO] ------------------------------------------------------------------------
  3. [INFO] BUILD SUCCESS
  4. [INFO] ------------------------------------------------------------------------
  5. [INFO] Total time: 01:30 min
  6. [INFO] Finished at: 2017-10-15T10:00:54+08:00
  7. [INFO] Final Memory: 31M/174M
  8. [INFO] ------------------------------------------------------------------------

在 IDEA 中执行 Application 类启动,任意正常模式或者 Debug 模式。可以在控制台看到成功运行的输出:

  1. ... 省略
  2. 2018-04-10 08:43:39.932 INFO 2052 --- [ctor-http-nio-1] r.ipc.netty.tcp.BlockingNettyContext : Started HttpServer on /0:0:0:0:0:0:0:0:8080
  3. 2018-04-10 08:43:39.935 INFO 2052 --- [ main] o.s.b.web.embedded.netty.NettyWebServer : Netty started on port(s): 8080
  4. 2018-04-10 08:43:39.960 INFO 2052 --- [ main] org.spring.springboot.Application : Started Application in 6.547 seconds (JVM running for 9.851)

打开 POST MAN 工具,开发必备。进行下面操作:

新增城市信息 POST http://127.0.0.1:8080/city

连接 MongoDB , 验证数据

连接 MongoDB

  1. docker run -it --rm --link mongo:mongo mongo mongo -u admin -p admin --authenticationDatabase admin mongo/admin

显示库列表:

  1. show dbs

使用某数据库

  1. use admin

显示表列表

  1. show collections

如果存在 city 表,格式化显示 city 表内容:

  1. db.city.find().pretty()

总结

这里,探讨了 Spring WebFlux 的如何整合 MongoDB 。整合其他存储 Cassandra、Redis、Couchbase,就大同小异了。下面,我们能会整合 Thymeleaf,更好的页面展示给大家。顺便让大家学习下 Thymeleaf 的基本用法。

转载,请保留原文地址,谢谢 ~

Spring Boot WebFlux 集成 Mongodb 数据源操作的更多相关文章

  1. Spring Boot:集成Druid数据源

    综合概述 数据库连接池负责分配.管理和释放数据库连接,它允许应用程序重复使用一个现有的数据库连接,而不是再重新建立一个:释放空闲时间超过最大空闲时间的数据库连接来避免因为没有释放数据库连接而引起的数据 ...

  2. Spring Boot WebFlux整合mongoDB

    引入maven文件 <dependency> <groupId>org.springframework.boot</groupId> <artifactId& ...

  3. Spring Boot 2 快速教程:WebFlux 集成 Mongodb(四)

    摘要: 原创出处 https://www.bysocket.com 「公众号:泥瓦匠BYSocket 」欢迎关注和转载,保留摘要,谢谢! 这是泥瓦匠的第104篇原创 文章工程:* JDK 1.8* M ...

  4. Spring Boot WebFlux 快速入门实践

    02:WebFlux 快速入门实践 Spring Boot 2.0 spring.io 官网有句醒目的话是: BUILD ANYTHING WITH SPRING BOOT Spring Boot ( ...

  5. Spring Boot (十四): 响应式编程以及 Spring Boot Webflux 快速入门

    1. 什么是响应式编程 在计算机中,响应式编程或反应式编程(英语:Reactive programming)是一种面向数据流和变化传播的编程范式.这意味着可以在编程语言中很方便地表达静态或动态的数据流 ...

  6. Java | Spring Boot Swagger2 集成REST ful API 生成接口文档

      Spring Boot Swagger2 集成REST ful API 生成接口文档 原文 简介 由于Spring Boot 的特性,用来开发 REST ful 变得非常容易,并且结合 Swagg ...

  7. Spring Boot中使用MongoDB数据库

    前段时间分享了关于Spring Boot中使用Redis的文章,除了Redis之后,我们在互联网产品中还经常会用到另外一款著名的NoSQL数据库MongoDB. 下面就来简单介绍一下MongoDB,并 ...

  8. Spring Boot WebFlux 增删改查完整实战 demo

    03:WebFlux Web CRUD 实践 前言 上一篇基于功能性端点去创建一个简单服务,实现了 Hello .这一篇用 Spring Boot WebFlux 的注解控制层技术创建一个 CRUD ...

  9. Spring Boot2 系列教程(二十五)Spring Boot 整合 Jpa 多数据源

    本文是 Spring Boot 整合数据持久化方案的最后一篇,主要和大伙来聊聊 Spring Boot 整合 Jpa 多数据源问题.在 Spring Boot 整合JbdcTemplate 多数据源. ...

随机推荐

  1. Winform中使用ZedGraph实现曲线图中字体去掉边框

    场景 Winforn中设置ZedGraph曲线图的属性.坐标轴属性.刻度属性: https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/details/10 ...

  2. git的几个小技巧

    git的几个小技巧 分享git的几个小技巧,后面会根据使用补充.目前包括git撤销本地修改.git回退到前n个版本.git多用户提交冲突解决.git 命令简化.欢迎大家补充^_* 1.git撤销本地修 ...

  3. Tomcat乱码

    日志乱码修改logging.properties文件中encoding=UTF-8 vim logging.properties encoding=utf-8 wq!保持退出,重启tomcat 乱码O ...

  4. 一套基于SpringBoot+Vue+Shiro 前后端分离 开发的代码生成器

    一.前言 最近花了一个月时间完成了一套基于Spring Boot+Vue+Shiro前后端分离的代码生成器,目前项目代码已基本完成 止步传统CRUD,进阶代码优化: 该项目可根据数据库字段动态生成 c ...

  5. cent OS 7 忘记 root 密码

    1. 在如下图, 选择系统的界面 按 e 2. 移动光标到文件底部, 修改如下两个地方(初始化 shell文件 并设置可读写), Ctrl x 退出并启动 shell 3. 如下界面 输入命令 mou ...

  6. JAVA设计模式-单例模式(Singleton)线程安全与效率

    一,前言 单例模式详细大家都已经非常熟悉了,在文章单例模式的八种写法比较中,对单例模式的概念以及使用场景都做了很不错的说明.请在阅读本文之前,阅读一下这篇文章,因为本文就是按照这篇文章中的八种单例模式 ...

  7. Codeforces Numbers 题解

    这题只需要会10转P进制就行了. PS:答案需要约分,可以直接用c++自带函数__gcd(x,y). 洛谷网址 Codeforces网址 Code(C++): #include<bits/std ...

  8. React + TypeScript 实现泛型组件

    泛型类型 TypeScript 中,类型(interface, type)是可以声明成泛型的,这很常见. interface Props<T> { content: T; } 这表明 Pr ...

  9. JS中数据类型转换

    JS中数据类型转换汇总 JS中的数据类型分为 [基本数据类型] 数字 number 字符串 string 布尔 boolean 空 null 未定义 undefined [引用数据类型] 对象 obj ...

  10. 读《深入理解Elasticsearch》点滴-Elastic HQ监控工具

    1.多节点监控 2.类似war功能部署,tomcat即可使用 3.免费 4.ElasticHQ supports all major version of Elasticsearch from ver ...