ZKX's LAB

SpringBoot怎么整合MongoDB?

2020-10-22新闻9

之前我们讲解了MongoDB在不同环境的安装和MongoDB的CRUD以及Robo3T可视化工具操作MongoDB,今天我们来看看实际业务中整合MongoDB的场景。本文我们主要是通过两种方法实现SpringBoot整合MongoDB,最后写一个小demo来理解MongoDB在实际业务中的应用。整合新建项目

新建一个SpringBoot项目,只需要勾选SpringWeb和SpringDataMongoDB的模块即可

通过Robo3T连接MongoDB数据库,确保数据库可用,也可以实时监测数据库情况。如果还没有配置Robo3T的可以看我这一篇博客

在MongoDB中新建一个databases,一会儿要用。SpringBoot中配置类

因为MongoDB默认是无密码的,我们这边没密码就空着#写服务器地址,本地就localhostspring.data.mongodb.host=localhost#用户名密码不同的库需要不同的认证,这里是在admin库中spring.data.mongodb.authentication-database=admin#有账户和密码就写,没有就空着spring.data.mongodb.username=spring.data.mongodb.password=spring.data.mongodb.port=27017#这里写刚才创建的数据库spring.data.mongodb.database=feng

我们先用MongoRepository接口来实现整合的方法

在项目中创建一个实体类packagecom.feng.pojo;/***

spirngboot-mongodb-test

*

**@author:Nicer_feng*@date:2020-10-1209:34**/publicclassUser{privateIntegerid;privateStringname;publicIntegergetId(){returnid;}publicvoidsetId(Integerid){this.id=id;}publicStringgetName(){returnname;}publicvoidsetName(Stringname){this.name=name;}publicUser(Integerid,Stringname){this.id=id;this.name=name;}@OverridepublicStringtoString(){return"User{"+"id="+id+",name='"+name+'\''+'}';}}

创建一个UserDao接口,这个接口要继承MongoRepository接口

我们可以发现MongoRepository接口中已经封装好了一些基础的方法,查询,增加等

UserDao.javapackagecom.feng.dao;importcom.feng.pojo.User;importorg.springframework.data.mongodb.repository.MongoRepository;/***

spirngboot-mongodb-test

*

**@author:Nicer_feng*@date:2020-10-1209:35**/publicinterfaceUserDaoextendsMongoRepository

{//啥也不用干,继承上面那个接口就行}

然后我们去测试类测试增加数据测试连接和插入packagecom.feng;importcom.feng.dao.UserDao;importcom.feng.pojo.User;importorg.junit.jupiter.api.Test;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.boot.test.context.SpringBootTest;@SpringBootTestclassSpirngbootMongodbTestApplicationTests{@AutowiredUserDaouserDao;@TestvoidcontextLoads(){}@TestpublicvoidaddUser(){Useruser=newUser();user.setId(1);user.setName("feng");userDao.insert(user);}}

运行测试方法,可以发现测试成功

在Robo3T中查询数据库,发现增加数据成功

当然我们也可以不用他MongoRepository封装的方法,我们可以自定义方法自定义接口方法

我们在MongoDB中多插入两个数据

在UserDao.java中加入方法publicinterfaceUserDaoextendsMongoRepository

{List

findUserByNameContaining(Stringname);}

测试类实现packagecom.feng;importcom.feng.dao.UserDao;importcom.feng.pojo.User;importorg.junit.jupiter.api.Test;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.boot.test.context.SpringBootTest;importjava.util.List;@SpringBootTestclassSpirngbootMongodbTestApplicationTests{@AutowiredUserDaouserDao;//******@TestvoidfindUserByNameContaining(){List

all=userDao.findAll();System.out.println(all);List

feng=userDao.findUserByNameContaining("fe");System.out.println(feng);}}查询结果

除了继承MongoRepository接口,我们还可以直接调用MongoTemplate,和RedisTemplate差不多,就是封装好的模板,直接创建对象调用对应方法即可。MongoTemplate实现

直接去测试类packagecom.feng;importcom.feng.dao.UserDao;importcom.feng.pojo.User;importorg.junit.jupiter.api.Test;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.boot.test.context.SpringBootTest;importorg.springframework.data.mongodb.core.MongoTemplate;importjava.util.List;@SpringBootTestclassSpirngbootMongodbTestApplicationTests{//****************@AutowiredMongoTemplatemongoTemplate;@TestvoidtestTemplate(){Useruser=newUser();user.setId(4);user.setName("冯半仙");mongoTemplate.insert(user);List

all=mongoTemplate.findAll(User.class);System.out.println(all);}}

可以看到findAll方法的参数必须是实体类的Class,所以我们传入User.class

测试运行

可以看到数据插入成功,并且查询成功

实际业务情况

我们知道非关系型数据库MongoDB一般就是做缓存功能,来提高web的程序的查询速度,将热点数据放在非关系型数据库中,而不是每次都去关系型数据库中查询的(如mysql),以下我们讲一个小demo,来模拟MongoDB做缓存的情况。但我们要知道实际业务中远比这复杂,比如缓存的时效性,哪些是热点数据(哪些数据需要缓存)等,这里的小demo并不考虑这些,只是参考一下思想

我们在进行查询时,缓存和数据库一般是这样配合的

MongoDB做缓存小Demo数据库

懒得新建项目也可以拿刚才的直接测哈,在数据里找了一圈发现有一个叫blog的比较合适,先看看数据表长什么样

建表语句CREATETABLE`blog`(`id`varchar(50)NOTNULLCOMMENT'博客id',`title`varchar(100)NOTNULLCOMMENT'博客标题',`author`varchar(30)NOTNULLCOMMENT'博客作者',`create_time`datetimeNOTNULLCOMMENT'创建时间',`views`int(30)NOTNULLCOMMENT'浏览量')ENGINE=InnoDBDEFAULTCHARSET=utf8

在SpringBoot项目中加入mysql依赖

org.springframework.boot

spring-boot-starter-jdbc

mysql

mysql-connector-java

runtime

在配置文件application.properties中加入mysql配置spring.datasource.username=root#自己的mysql数据库密码spring.datasource.password=*****#自己把上面的表建立在哪个库中,就连哪个库spring.datasource.url=jdbc:mysql://localhost:3306/mybatis?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver

创建实体类Blog.javapackagecom.feng.pojo;importjava.util.Date;/***

spirngboot-mongodb-test

*

**@author:Nicer_feng*@date:2020-10-1210:10**/publicclassBlog{privateIntegerid;privateStringtitle;privateStringauthor;privateDatecreate_time;privateIntegerviews;publicBlog(){}publicBlog(Integerid,Stringtitle,Stringauthor,Datecreate_time,Integerviews){this.id=id;this.title=title;this.author=author;this.create_time=create_time;this.views=views;}publicIntegergetId(){returnid;}publicvoidsetId(Integerid){this.id=id;}publicStringgetTitle(){returntitle;}publicvoidsetTitle(Stringtitle){this.title=title;}publicStringgetAuthor(){returnauthor;}publicvoidsetAuthor(Stringauthor){this.author=author;}publicDategetCreate_time(){returncreate_time;}publicvoidsetCreate_time(Datecreate_time){this.create_time=create_time;}publicIntegergetViews(){returnviews;}publicvoidsetViews(Integerviews){this.views=views;}@OverridepublicStringtoString(){return"Blog{"+"id="+id+",title='"+title+'\''+",author='"+author+'\''+",create_time="+create_time+",views="+views+'}';}}测试

直接去SpringBoot测试类,我们什么都先用模板类实现,这里面我们先测试一个查询,代码逻辑就是先从缓存(MongoDB)中查,如果缓存中有,直接返回,如果缓存中没有,我们去关系型数据库(MySQL)中查询,并将查询的结果存入缓存中,下次再查询直接返回结果。packagecom.feng;importcom.feng.dao.UserDao;importcom.feng.pojo.Blog;importcom.feng.pojo.User;importorg.junit.jupiter.api.Test;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.boot.test.context.SpringBootTest;importorg.springframework.data.mongodb.core.MongoTemplate;importorg.springframework.data.mongodb.core.query.Criteria;importorg.springframework.data.mongodb.core.query.Query;importorg.springframework.jdbc.core.JdbcTemplate;importjava.sql.SQLException;importjava.util.Date;importjava.util.List;importjava.util.Map;importjava.util.Set;@SpringBootTestclassSpirngbootMongodbTestApplicationTests{//********@AutowiredMongoTemplatemongoTemplate;@AutowiredJdbcTemplatejdbcTemplate;@TestvoidgetBlogByTitle()throwsSQLException{Stringtitle="Java如此简单2";Queryquery=newQuery(Criteria.where("title").is(title));Blogone=mongoTemplate.findOne(query,Blog.class);if(one!=null){System.out.println("从缓存数据库直接拿的数据:"+one);}else{Stringsql="SELECT*FROMmybatis.blogWHEREblog.title=?";List

>maps=jdbcTemplate.queryForList(sql,"Java如此简单2");System.out.println("从mysql数据库拿的数据:"+maps.toString());Map

map=maps.get(0);Set

strings=map.keySet();System.out.println(strings);Blogblog=newBlog();blog.setId(Integer.valueOf(map.get("id").toString()));blog.setTitle((String)map.get("title"));blog.setAuthor((String)map.get("author"));blog.setCreate_time((Date)map.get("create_time"));blog.setViews((Integer)map.get("views"));System.out.println(blog.toString());mongoTemplate.insert(blog);//这里不能直接把从jdbc模板类返回的对象存到MongoDB中,因为queryForList返回的对象并不是我们的实体类对象,我们要手动转存再存到缓存中//mongoTemplate.insert(maps);System.out.println("mysql拿的数据存到缓存中啦!");}}}

第一次查询,缓存中无结果,在数据库中查到,并存入缓存中

第二次查询,直接从缓存中拿到结果并返回

那既然思路和测试没问题,咱模拟的像一点,整个业务出来吧

在项目中创建controller和service文件夹

分别创建BlogController和BlogServiceBlogController.javapackagecom.feng.controller;importcom.feng.pojo.Blog;importcom.feng.service.BlogService;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.web.bind.annotation.GetMapping;importorg.springframework.web.bind.annotation.PathVariable;importorg.springframework.web.bind.annotation.RestController;/***

spirngboot-mongodb-test

*

**@author:Nicer_feng*@date:2020-10-1211:27**/@RestControllerpublicclassBlogController{@AutowiredBlogServiceblogService;@GetMapping("getBlog/{title}")publicBloggetBlog(@PathVariableStringtitle){BlogblogByTitle=blogService.getBlogByTitle(title);returnblogByTitle;}}我们这里类名使用@RestController注解声明该类为一个控制器,并且返回JSON字符串给前端。BlogService.javapackagecom.feng.service;importcom.feng.pojo.Blog;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.data.mongodb.core.MongoTemplate;importorg.springframework.data.mongodb.core.query.Criteria;importorg.springframework.data.mongodb.core.query.Query;importorg.springframework.jdbc.core.JdbcTemplate;importorg.springframework.stereotype.Service;importjava.util.Date;importjava.util.List;importjava.util.Map;importjava.util.Set;/***

spirngboot-mongodb-test

*

**@author:Nicer_feng*@date:2020-10-1211:27**/@ServicepublicclassBlogService{@AutowiredMongoTemplatemongoTemplate;@AutowiredJdbcTemplatejdbcTemplate;publicBloggetBlogByTitle(Stringtitle){Queryquery=newQuery(Criteria.where("title").is(title));Blogone=mongoTemplate.findOne(query,Blog.class);if(one!=null){System.out.println("从缓存数据库直接拿的数据:"+one);}else{Stringsql="SELECT*FROMmybatis.blogWHEREblog.title=?";List

>maps=jdbcTemplate.queryForList(sql,title);System.out.println("从mysql数据库拿的数据:"+maps.toString());Map

map=maps.get(0);Set

strings=map.keySet();System.out.println(strings);Blogblog=newBlog();blog.setId(Integer.valueOf(map.get("id").toString()));blog.setTitle((String)map.get("title"));blog.setAuthor((String)map.get("author"));blog.setCreate_time((Date)map.get("create_time"));blog.setViews((Integer)map.get("views"));mongoTemplate.insert(blog);one=blog;System.out.println("mysql拿的数据存到缓存中啦!");}returnone;}}

这里面的逻辑跟这张图一致

@Service 表示该类为一个service(事务处理),可以被注入到其他对象(Spring帮你管理)。

@Autowired表示要注入对象的意思。而MongoTemplate 就是已经封装好在Spring中操作MongoDB的对象。测试

启动SpringBoot启动类,访问8080端口

第一次我们查询缓存中有的数据,第二次查询缓存中不存在的数据,可以看到第一次直接返回缓存中的结果,而第二次是先从数据库中拿,然后将数据保存到缓存中,再返回给前端

缓存需要注意的问题

我们是用缓存保存热点数据的时候可能很少有更新或者删除的请款,但并不代表我们遇不到这种情况,所以我们在BlogService中还要添加一个updateBlogByTitle(String title,Integer views),方法主要是用来更新数据库和MongoDB缓存中的数据库缓存数据的修改注意缓存一致性

在BlogSerivce中添加update方法publicbooleanupdateBlogByTitle(Stringtitle,Integerviews){try{Queryquery=newQuery(Criteria.where("title").is(title));Updateupdate=newUpdate();update.set("views",views);mongoTemplate.upsert(query,update,Blog.class);Stringsql="updatemybatis.blogsetviews=?wheretitle=?";intisUpdate=jdbcTemplate.update(sql,views,title);if(isUpdate==0){returnfalse;}}catch(Exceptione){returnfalse;}returntrue;}

controller配置对应视图层@GetMapping("updateBlog")publicStringupdateBlog(Stringtitle,Integerviews){booleanb=blogService.updateBlogByTitle(title,views);returnb?"updatesuccess":"updatefailed";}运行

运行SpringBoot主类,访问项目地址

http://localhost:8080/updateBlog?title=Java如此简单&views=5533

可以发现缓存和数据库中的数据均更新成功

缓存数据的删除

service添加删除逻辑publicbooleandeleteBlogByTitle(Stringtitle){try{Queryquery=newQuery(Criteria.where("title").is(title));mongoTemplate.remove(query,Blog.class);Stringsql="deletefrommybatis.blogwheretitle=?";intisDel=jdbcTemplate.update(sql,title);if(isDel==0){returnfalse;}}catch(Exceptione){returnfalse;}returntrue;}

controller添加视图@GetMapping("delete/{title}")publicStringdeleteBlog(@PathVariableStringtitle){booleanb=blogService.deleteBlogByTitle(title);returnb?"deletesuccess":"deletefailed";}测试

访问 http://localhost:8080/delete/MongoDB如此简单 发现缓存和数据库中的数据均被删除

最后添加的逻辑也基本一致,这里不再赘述,感兴趣的同学可以继续测试!做缓存时最重要的就是数据的一致性,千万不要出现缓存和数据库中的数据不一致的情况。

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。

本文链接:

https://blog.csdn.net/weixin_43876186/article/details/109027368

#技术编程

随机阅读

qrcode
访问手机版