前言

SpringBoot是常用开发框架,而MongoDB也是最近越来越火的非关系型数据库,这里使用SpringBoot+MongoDB实现一个小案例,当然MongoDB实际做缓存的可能不多,但是这里仅仅为了一个小demo简单的学习使用,入门上手为目的,更多的复杂查询还需关注MongoDB官网。

如果本篇对你有帮助,还请点赞支持一下!微信搜索 bigsai 回复bigsai获取珍藏学习pdf一份!

如果对MongoDB不太了解,还请先看上篇 MongoDB从立地到成佛 。

创建MongoDB数据库和项目

创建MongoDB数据库

打开Studio 3T数据库管理工具,连接本地MongoDB数据库之后,创建名为test的数据库,在test数据库中创建名为news得集合:

springboot 支持mysql和mongodb springboot连接mongodb数据库_实现一个简单的dhcp平衡器c++

创建项目

首先,打开IDEA创建项目,选择创建Springboot项目: 

springboot 支持mysql和mongodb springboot连接mongodb数据库_java连接mongodb_02

然后在选择Gruop和Aritifact时候分别填写 com 和 mongodemo ,Java Version选择8版本。 

springboot 支持mysql和mongodb springboot连接mongodb数据库_实现一个简单的dhcp平衡器c++_03

在勾选模块时候,这里勾选Spring web、MongoDB依赖模块,选择合适位置创建项目,项目就可以成功创建:

springboot 支持mysql和mongodb springboot连接mongodb数据库_java连接mongodb_04

预备工作

创建完项目,我们需要做一些预备工作用来完成缓存。我们首先要在项目中的application.properties中添加配置连接到数据库,配置规则为:spring.data.mongodb.uri=mongodb://地址:端口/数据库名 ,使用方法英文本案例使用本地的MongoDB数据库,默认端口为27017,而使用的MongoDB具体数据库名称为test,那么就可以按照以下进行配置:

spring  .  data  .  mongodb  .  uri  =  mongodb  :   /   /  localhost  :   27017   /  test  

 spring  .  data  .  mongodb  .  uri  =  mongodb  :   /   /  localhost  :   27017   /  test

这样在项目中就可以连接到本地的MongoDB的test数据库并访问。

其次在项目中com.mongodb目录下分别创建controller,service,pojo文件夹,在controller文件夹下创建 newsController.java 类,为负责url和逻辑的控制器:

package  com  .  mongodemo  .  controller  ;   import  org  .  slf4j  .  Logger  ;   import  org  .  slf4j  .  LoggerFactory  ;   import  org  .  springframework  .  web  .  bind  .  annotation  .  RestController  ;   @RestController   public   class   newsController   {   private   static  Logger logger  =  LoggerFactory  .   getLogger   (  newsController  .   class   )   ;   }   

 package  com  .  mongodemo  .  controller  ;   import  org  .  slf4j  .  Logger  ;   import  org  .  slf4j  .  LoggerFactory  ;   import  org  .  springframework  .  web  .  bind  .  annotation  .  RestController  ;   @RestController   public   class   newsController   {   private   static  Logger logger  =  LoggerFactory  .   getLogger   (  newsController  .   class   )   ;   }

其中:

  • @RestController就声明该类为一个控制器,并且返回JSON字符串给前端。
  • 而Logger对象用于打印日志。在web项目中我们更倾向于使用log打印日志而不在控制台直接输出。

controller创建完毕在service 文件夹下创建 NewsService.java 类,里面先编写以下内容:

package  com  .  mongodemo  .  service  ;   import  org  .  slf4j  .  Logger  ;   import  org  .  slf4j  .  LoggerFactory  ;   import  org  .  springframework  .  beans  .  factory  .  annotation  .  Autowired  ;   import  org  .  springframework  .  data  .  mongodb  .  core  .  MongoTemplate  ;   import  org  .  springframework  .  stereotype  .  Service  ;   @Service   public   class   NewsService   {   private   static  Logger logger  =  LoggerFactory  .   getLogger   (  NewsService  .   class   )   ;   @Autowired  MongoTemplate mongoTemplate  ;   }   

 package  com  .  mongodemo  .  service  ;   import  org  .  slf4j  .  Logger  ;   import  org  .  slf4j  .  LoggerFactory  ;   import  org  .  springframework  .  beans  .  factory  .  annotation  .  Autowired  ;   import  org  .  springframework  .  data  .  mongodb  .  core  .  MongoTemplate  ;   import  org  .  springframework  .  stereotype  .  Service  ;   @Service   public   class   NewsService   {   private   static  Logger logger  =  LoggerFactory  .   getLogger   (  NewsService  .   class   )   ;   @Autowired  MongoTemplate mongoTemplate  ;   }

其中:

  • @Service 表示该类为一个service(事务处理),可以被注入到其他对象(Spring帮你管理)。
  • @Autowired表示要注入对象的意思。而MongoTemplate 就是已经封装好在Spring中操作MongoDB的对象。

service创建完成,我们需要在pojo中创建news类,代表新闻实体内容。

import  java  .  util  .  Date  ;   public   class   news   {   private  String title  ;   private  Date date  ;   private  String brief  ;   private  String content  ;   private  String author  ;   @Override   public  String  toString   (   )   {   return   "news{"   +   "   +  title  +   '\''   +   ", date="   +  date  +   ", brief='"   +  brief  +   '\''   +   ", content='"   +  content  +   '\''   +   ", author='"   +  author  +   '\''   +   '}'   ;   }   public   news   (  String title  ,  Date date  ,  String brief  ,  String content  ,  String author  )   {   this   .  title  =  title  ;   this   .  date  =  date  ;   this   .  brief  =  brief  ;   this   .  content  =  content  ;   this   .  author  =  author  ;   }   public  String  getTitle   (   )   {   return  title  ;   }   public   void   setTitle   (  String title  )   {   this   .  title  =  title  ;   }   public  Date  getDate   (   )   {   return  date  ;   }   public   void   setDate   (  Date date  )   {   this   .  date  =  date  ;   }   public  String  getBrief   (   )   {   return  brief  ;   }   public   void   setBrief   (  String brief  )   {   this   .  brief  =  brief  ;   }   public  String  getContent   (   )   {   return  content  ;   }   public   void   setContent   (  String content  )   {   this   .  content  =  content  ;   }   public  String  getAuthor   (   )   {   return  author  ;   }   public   void   setAuthor   (  String author  )   {   this   .  author  =  author  ;   }   }   
import  java  .  util  .  Date  ;   public   class   news   {   private  String title  ;   private  Date date  ;   private  String brief  ;   private  String content  ;   private  String author  ;   @Override   public  String  toString   (   )   {   return   "news{"   +   "   +  title  +   '\''   +   ", date="   +  date  +   ", brief='"   +  brief  +   '\''   +   ", content='"   +  content  +   '\''   +   ", author='"   +  author  +   '\''   +   '}'   ;   }   public   news   (  String title  ,  Date date  ,  String brief  ,  String content  ,  String author  )   {   this   .  title  =  title  ;   this   .  date  =  date  ;   this   .  brief  =  brief  ;   this   .  content  =  content  ;   this   .  author  =  author  ;   }   public  String  getTitle   (   )   {   return  title  ;   }   public   void   setTitle   (  String title  )   {   this   .  title  =  title  ;   }   public  Date  getDate   (   )   {   return  date  ;   }   public   void   setDate   (  Date date  )   {   this   .  date  =  date  ;   }   public  String  getBrief   (   )   {   return  brief  ;   }   public   void   setBrief   (  String brief  )   {   this   .  brief  =  brief  ;   }   public  String  getContent   (   )   {   return  content  ;   }   public   void   setContent   (  String content  )   {   this   .  content  =  content  ;   }   public  String  getAuthor   (   )   {   return  author  ;   }   public   void   setAuthor   (  String author  )   {   this   .  author  =  author  ;   }   }

其中各个字段分别表示为:

名称

含义

title

标题

date

日期

brief

概要

content

内容

author

作者

缓存查询

下面开始实战MongoDB实现一个新闻得缓存功能,实现缓存之前,要清楚缓存的核心作用:提升web程序的 查询速度 ,将热点数据放到非关系数据库中。本案例对接口进行缓存,不过真正的缓存实例需要考虑很多问题比如时效性,缓存那些数据等。在这里主要为了讲解MongoDB的一个实例。

在查询时候,缓存和数据库之间通常是这么配合的:

springboot 支持mysql和mongodb springboot连接mongodb数据库_java连接mongodb_05

为了降低整个项目的复杂度,这里用手动生成的数据对象代替成数据库中查询的数据,我们在NewsService中编写getNewsByTitle(String title)函数,其功能是根据标题返回缓存或数据库中该条news数据,如果MongoDB中存在则直接返回该对象,否则先从数据库查询(这里直接生成),然后存到MongoDB中再返回。具体代码为:

public  news  getNewsByTitle   (  String title  )   {   //查询数据先从MongoDB中查询  Query query  =   new   Query   (  Criteria  .   where   (   "title"   )   .   is   (  title  )   )   ;  news news  =  mongoTemplate  .   findOne   (  query  ,  news  .   class   )   ;   if   (  news  ==  null  )   //缓存中没该条记录   {  logger  .   info   (   "从数据库查询数据"   )   ;   //假设news1从数据库中查询  news news1  =   new   news   (  title  ,   new   Date   (   )   ,   ""   ,   ""   ,   "bigsai"   )   ;  news1  .   setBrief   (   "有了博学谷,妈妈再也不用担心我的java学习!"   )   ;  news1  .   setContent   (   "博学谷优质学习资料为java学习提供更好环境,越来越多开发者学习使用"   )   ;  mongoTemplate  .   insert   (  news1  ,   "news"   )   ;  logger  .   info   (   "数据插入到MongoDB成功"   )   ;  news  =  news1  ;   }   else   {  logger  .   info   (   "数据从缓存访问成功"   )   ;   }   return  news  ;   }   


public  news  getNewsByTitle   (  String title  )   {   //查询数据先从MongoDB中查询  Query query  =   new   Query   (  Criteria  .   where   (   "title"   )   .   is   (  title  )   )   ;  news news  =  mongoTemplate  .   findOne   (  query  ,  news  .   class   )   ;   if   (  news  ==  null  )   //缓存中没该条记录   {  logger  .   info   (   "从数据库查询数据"   )   ;   //假设news1从数据库中查询  news news1  =   new   news   (  title  ,   new   Date   (   )   ,   ""   ,   ""   ,   "bigsai"   )   ;  news1  .   setBrief   (   "有了博学谷,妈妈再也不用担心我的java学习!"   )   ;  news1  .   setContent   (   "博学谷优质学习资料为java学习提供更好环境,越来越多开发者学习使用"   )   ;  mongoTemplate  .   insert   (  news1  ,   "news"   )   ;  logger  .   info   (   "数据插入到MongoDB成功"   )   ;  news  =  news1  ;   }   else   {  logger  .   info   (   "数据从缓存访问成功"   )   ;   }   return  news  ;   }

上面的代码中:

  • 我们核心使用mongoTemplate对象来实现查询一条记录,查询语句为:mongoTemplate.findOne(query, news.class),第一个参数为查询的条件,第二个参数为查询结果转成Java对象的类型,它帮你自动处理。
  • 通过Query对象来辅助我们实现条件查询,这里的意思就是查询条件为:MongoDB中title字段为传进来title字符串的该条记录。
  • 而插入的语法为 mongoTemplate.insert(news1,“news”),第一个参数为插入的文档记录,第二个参数为连接呃MongoDB对应数据库下的集合(Collections)。

在newsController中,我们编写一个名称为getnews的接口,用来给用户返回该标题新闻(news类)的一条数据的JSON文件,具体代码为:

@Autowired  NewsService newsService  ;   @GetMapping   (   "getnews/{title}"   )   public  news  getnews   (   @PathVariable  String title  )   {  news news  =  newsService  .   getNewsByTitle   (  title  )   ;   return  news  ;   }   
 @Autowired  NewsService newsService  ;   @GetMapping   (   "getnews/{title}"   )   public  news  getnews   (   @PathVariable  String title  )   {  news news  =  newsService  .   getNewsByTitle   (  title  )   ;   return  news  ;   }

上面代码中:

  • @Autowired(required = false)用来注入对象,下面的NewsService userService就是被注入的对象,雅思周末班注入之后不需要手动创建对象可以直接使用(Spring帮你管理)
  • @GetMapping(“getnews/{title}”) 意为声明一个get请求方式的接口,

我们启动程序,浏览器输入 localhost:8080/getnews/好好学java 页面会有返回的结果,返回的一个news对象序列化成JSON的字符串的文本。 

springboot 支持mysql和mongodb springboot连接mongodb数据库_springboot整合mongodb_06

同时,你查看IDEA的日志,由于第一次查询,MongoDB中没有对应数据你会发现会先从数据库中查询然后存储到MongoDB中: 

springboot 支持mysql和mongodb springboot连接mongodb数据库_springboot整合mongodb_07

查看MongoDB的news集合发现记录被成功插入了,多刷新页面 localhost:8080/getnews/好好学java 你会发现数据会直接从MongoDB中返回: 

springboot 支持mysql和mongodb springboot连接mongodb数据库_springboot整合mongodb_08

缓存更新、删除

缓存中的数据和存储的关系数据库的数据是一致的,当我们只有查询操作的时候,可以一直保持数据的一致性,但是我们如果对数据有更新、删除的操作,就需要对关系数据库和MongoDB中的数据同时进行更新或删除的操作,让数据再次达到一致性的效果。

缓存更新

虽然大部分情况我们对热点新闻数据可能很少更新,但是也有时候新闻中有部分内容需要更改的需要我们完成,比如比分错字或者不妥的言论。

我们在NewsService中编写updateNewsContentByTitle((String title,String content)函数,其作用为更新数据库(这里没有具体实现)和MongoDB缓存中的数据:

public   boolean   updateNewsContentByTitle   (  String title  ,  String content  )   {   try   {  Query query  =   new   Query   (  Criteria  .   where   (   "title"   )   .   is   (  title  )   )   ;  Update update  =   new   Update   (   )   ;  update  .   set   (   "content"   ,  content  )   ;   //更新内容  update  .   set   (   "date"   ,   new   Date   (   )   )   ;   //更新时间   // 假设在这里数据库中更新过这里跳过   // updateFirst 更新查询返回结果集的第一条   //upsert 更新如果不存在就插入  mongoTemplate  .   upsert   (  query  ,  update  ,  news  .   class   )   ;   }   catch   (   Exception  e  )   {   return   false   ;   }   return   true   ;   }   

 public   boolean   updateNewsContentByTitle   (  String title  ,  String content  )   {   try   {  Query query  =   new   Query   (  Criteria  .   where   (   "title"   )   .   is   (  title  )   )   ;  Update update  =   new   Update   (   )   ;  update  .   set   (   "content"   ,  content  )   ;   //更新内容  update  .   set   (   "date"   ,   new   Date   (   )   )   ;   //更新时间   // 假设在这里数据库中更新过这里跳过   // updateFirst 更新查询返回结果集的第一条   //upsert 更新如果不存在就插入  mongoTemplate  .   upsert   (  query  ,  update  ,  news  .   class   )   ;   }   catch   (   Exception  e  )   {   return   false   ;   }   return   true   ;   }

其中:

  • Query对象来辅助我们实现条件查询待更新数据,这里的意思就是查询条件同样为:MongoDB中title字段为传进来title字符串的该条记录。
  • Update对象用来记录更新的字段和数据,这里更新传进来的content内容和date日期。
  • mongoTemplate.upsert(query, update, news.class)用来实现更新,如果MongoDB中不存在该数据那么就插入到MongoDB中。

编写完service,在newsController中编写一个名为updatenews的接口,用来更新数据库数据和缓存在MongoDB的数据:

@GetMapping   (   "updatenews"   )   public  String  updatenews   (  String title  ,  String content  )   {   boolean  bool  =  newsService  .   updateNewsContentByTitle   (  title  ,  content  )   ;   if   (  bool  )   return   "更新成功"   ;   else   return   "更新失败"   ;   }  
@GetMapping   (   "updatenews"   )   public  String  updatenews   (  String title  ,  String content  )   {   boolean  bool  =  newsService  .   updateNewsContentByTitle   (  title  ,  content  )   ;   if   (  bool  )   return   "更新成功"   ;   else   return   "更新失败"   ;   }

启动程序访问 localhost:8080/updatenews?title=好好学java&content=学好java走遍全天下 ,你会发现数据更新成功: 

springboot 支持mysql和mongodb springboot连接mongodb数据库_java连接mongodb_09

缓存删除

除了更新的时候需要保证数据一致性,删除的时候也需要保证数据一致性,如果在删除关系数据库的数据而不删除MongoDB缓存,那么下次查询该条数据MongoDB中存在而关系数据库中不存在,这样就造成了数据不一致,所以在删除数据的时候我们需要在MongoDB中的数据也删除。

在NewsService中编写deleteNewsByTitle(String title)函数,用来根据标题title删除MongoDB中的记录:

public   boolean   deleteNewsByTitle   (  String title  )   {   try   {  Query query  =   new   Query   (  Criteria  .   where   (   "title"   )   .   is   (  title  )   )   ;  mongoTemplate  .   remove   (  query  ,  news  .   class   )   ;   }   catch   (   Exception  e  )   {   return   false   ;   }   return   true   ;   }   
public   boolean   deleteNewsByTitle   (  String title  )   {   try   {  Query query  =   new   Query   (  Criteria  .   where   (   "title"   )   .   is   (  title  )   )   ;  mongoTemplate  .   remove   (  query  ,  news  .   class   )   ;   }   catch   (   Exception  e  )   {   return   false   ;   }   return   true   ;   }

mongoTemplate.remove(query,news.class);意味从MongoDB中删除满足查询条件的记录。其中query为查询条件,news.class为删除对象在Java中的类。

在newsController中编写deletenews接口,用来处理删除的请求:

@GetMapping   (   "deletenews/{title}"   )   public  String  deletenews   (   @PathVariable  String title  )   {   try   {  newsService  .   deleteNewsByTitle   (   "好好学java"   )   ;   return   "删除成功"   ;   }   catch   (   Exception  e  )   {   return   "删除失败"   ;   }   } 
 @GetMapping   (   "deletenews/{title}"   )   public  String  deletenews   (   @PathVariable  String title  )   {   try   {  newsService  .   deleteNewsByTitle   (   "好好学java"   )   ;   return   "删除成功"   ;   }   catch   (   Exception  e  )   {   return   "删除失败"   ;   }   }

启动程序,访问 http://localhost:8080/deletenews/好好学java ,会发现缓存在MongoDB中的记录被成功删除,这样就保证MongoDB中不会出现关系数据库中不存在的脏数据,达到数据一致性! 

springboot 支持mysql和mongodb springboot连接mongodb数据库_java连接mongodb_10