入门:MongoDB基本命令及整合Springboot使用

在这里插入图片描述

MongoDB


1、基本概述

MongoDB是以JSON为数据模型的文档型介于关系数据库和非关系数据库之间的产品(虽然更多称它为非关系数据库)。它直接操作的对象是内存,通过映射把数据持久化到硬盘

MongoDB追求一个对象一个数据表,无论对象与对象之间存在怎样的关系,它的表与表之间是没有关联性的。因此,对于关联关系,我们只需要在类中维护好它们的关系就好。因此严格来说,MongoDB又不属于数据库,它应该是一种以数据结构化存储方法的集合

MongoDB 将数据存储为一个文档,数据结构由键值(key=>value)对组成,其文档就是一堆JSON数据,只是这些JSON数据基本是嵌套型的。


2、与MySql的区别
  • 在Mysql等关系型数据库中需要建立和查询两个表才能完成的事情在MongoDB中只需要一个集合嵌套就能搞定。

  • Mysql关系型数据库有事务的ACID,而MongoDB是没有事务

  • 名词

    ​ mysql | mongodb


    ​ table表 | collection集合


    ​ row行 | document文档/数据记录行


    ​ column列 | field数据字段/域


  • mysql的缺点:

    • 为了维护执行需要消耗大量的性能

    • 影响读写

    • 固定的表结构

    • 高并发读写需求


  • mongodb的缺点:

    • 主要是无事务处理
    • 不提供sql支持

mongodb关联表设计

//一对一和多对一
{
	id:xxx
	name:xxx
	other:{
		id:xxx
		name:Xxx
		...
	}
	...
}

//一对多和多对多
{
	id:xxx
	name:xxx
	other:[
		{id:xxx,name:Xxx},
		{id:xxxx,name:Xxxx}
		...
		]
	...
}

3、MySql、MongDB、Redis选择
  • 如果需要将mongodb作为后端db来代替mysql使用,即这里mysql与mongodb 属于平行级别,那么,这样的使用可能有以下几种情况的考量:
    • mongodb所负责部分以文档形式存储,能够有较好的代码亲和性,json格式的直接写入方便(如日志之类)
    • 从datamodels设计阶段就将原子性考虑于其中,无需事务之类的辅助。开发用如nodejs之类的语言来进行开发,对开发比较方便。
    • mongodb本身的failover机制,无需使用如MHA之类的方式实现
  • 将mongodb作为类似redis 、memcache来做缓存db,为mysql提供服务,或是后端日志收集分析。 考虑到mongodb属于nosql型数据库,sql语句与数据结构不如mysql那么亲和 ,也会有很多时候将mongodb做为辅助mysql而使用的类redis、memcache 之类的缓存db来使用。 亦或是仅作日志收集分析。或者是存储某文章相关的评论,n方级别的数据(sql是中间表的形式,数据量太大)

4、MongoDB语法

MongoDB底层是js,其操作语法与js相似,格式为:db.集合名.操作

进入monogodb的bin目录下执行

>./mongo;  //进入mongodb
...
....
.....
>show dbs;  //查看数据库
user   0.012GB
>use user;   //进入user数据库
switched to db user
>show collections;  //查看集合或者使用show tables
login_log
>db.login_log.find();  //查询login_log的所有文档
.....
1、创建集合
db.createCollection("user")  //创建一个user集合
2、CRUD

1.新增操作

db.user.insert({name:"xiaoming",age:18})  //首次操作insert会直接创建表uesr

2.修改操作

db.集合名.update({条件键:条件值}, {$set:{更新键:更新值}})

db.user.update({name:"xiaoming"},{$set:{name:"dabao"}})  //修改条件为name=xiaoming的文档,其name改为dabao

3.删除操作

db.user.deleteMany({})  //删除user集合
db.user.delete({name:"dabao"})  //删除条件为name=dabao的文档

4.查询操作

db.集合名.find({条件键:条件值}, {显示键1:显示值1, 显示键2:显示值2, …})

db.user.find()  //查找user所有文档
db.user.find({},{name:0})  //查询所有,但不显示name列
db.user.find({},{name:1,age=1})  //查询所有,仅显示name、age列
db.user.find({gender:1}, {name:1, age:1})  //查询gender=1的文档,仅显示name、age列

db.user.findOne({name: dabao})  //查询一条数据

3、算术运算
db.<集合名>.find({<key>: {$gt:<value>}})  //$gt、$gte、$lt、$lte,大于、大于等于、小于、小于等于

db.<集合名>.find({<key>: <value>})  //等于

4、条件
db.user.find({age: {$gt:30}})  //查询age大于30的所有user
db.user.find({age: {$gte:3, $lte:5}})  //查询age大于等于3且小于等于5的user

db.student.find({"_id":ObjectId("5c89ecd012c1bcb23ed4e906")})  //根据id查询

5、MongDB数据类型

跟java类似

类型别名
Doubledouble
Stringstring
Objectobject
Arrayarray
Binary databinData
Undefinedundefined
ObjectIdobjectId
Boolean“bool”
Date“date”
Null“null”
Regular Expression“regex”
DBPointer“dbPointer”
JavaScript“javascript”
Symbol“symbol”
JavaScript(with scope)“javascriptWithScope”
32-bit integer“int”
Timestamp“timestamp”
64-bit integer“long”
Min key“minKey”
Max key“maxKey”

6、SpringBoot集成MongoDB

application.properties配置数据源

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

①依赖

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

②domain

@Data
@Document("user")  
@TableName("user")
public class User{    
	@Id    //注意,贴了@Id注解后,springmvc自动映射MongoDB的数据类型为ObjectId的_id 
	private String id;     
	private String name;    
	//...
}

repository层(即mysql的dao/mapper层)通用接口

public interface UserRepository extends MongoRepository<T,T>{    
	//泛型1对应的是domain,泛型2对应的是主键id的类型,基本上就是String    
	User findByName(String name);
}

④service层

MongoDB没有通用service接口层,里面的方法都需要自己手写并且实现

mongodb启动器实现了JPA规范,针对查询操作(当然有其他操作的能力)非常友好,先来看一个方法

public interface IUserService{    
	//....
}

直接根据repository中的方法名实现对应的方法,怎么做到的?先来了解JPA规范


1、JPA规范

JPA就是Java Persistence API,即用于对象持久化的 API,Java EE 5.0 平台标准的 ORM 规范,使得应用程序以统一的方式访问持久层。


使用JPA的优势:

(1) 标准化: 提供相同的 API,这保证了基于JPA 开发的企业应用能够经过少量的修改就能够在不同的 JPA 框架下运行。

(2) 简单易用,集成方便: JPA 的主要目标之一就是提供更加简单的编程模型,在 JPA 框架下创建实体和创建 Java 类一样简单,只需要使用 javax.persistence.Entity 进行注释;JPA 的框架和接口也都非常简单,

(3) 可媲美JDBC的查询能力: JPA的查询语言是面向对象的,JPA定义了独特的JPQL,而且能够支持批量更新和修改、JOIN、GROUP BY、HAVING 等通常只有 SQL 才能够提供的高级查询特性,甚至还能够支持子查询。

(4) 支持面向对象的高级特性: JPA 中能够支持面向对象的高级特性,如类之间的继承、多态和类之间的复杂关系,最大限度的使用面向对象的模型

回过头来,mongodb通过实现JPA规范,对方法名拆解,如findByName:find查询,By一个,Name属性为name的字段(域),通过方法名直接猜测方法的实现,只要方法名符合规范,返回值对应需求和真实结果即可。

但是,如果我们需要多条件查询的时候,如

@Query("{$and:[{'stu_name':?0},{'age':?1}]}")
List<Student> findStudentsByStu_nameAndAge(String stu_name,Integer age);

这个情况就会造成方法名称变得特别长


==》解决:使用MongoTemplate

2、MongoTemplate

MongoTemplate:MongoReposity的底层实现,MongoReposity只能操作实现它的对应对象,而MongoTemplate能够操作所有实现了MongoRepository<T,T>的对象,它提供统一API对MongoDB进行操作,对应的CRUD有不同的拼接类(跟mp操作mysql的Wrapper接口下的QueryWrapper和UpdateWrapper一样)。

MongoTemplate的API需要程序员提供已拼接的语句、操作对象作为参数,CRUD中:

  • 新增操作只需要提供操作对象
  • 删除对象需要提供语句拼接对象Query和操作对象
  • 修改操作需要提供语句拼接对象Update和操作对象
  • 查询操作需要提供语句拼接对象Query和操作对象

MongoTemplate和其他拼接类所在的都包是core包

public class Test{    
	@Test    
	public void InsertTest(){        
		MongoTemplate mongoTemplate = new MongoTemplate();                
		mongoTemplate.save(new Student(null, "张三", 15, 1, null));  
		//id由mdb提供        
		//Document模式        
		Document document=new Document()                
		.append("name","张三")                
		.append("age",15)                
		.append("grade_id",1);        
		mongoTemplate.save(document,"student");        
		//如果有对应的student对象请求封装传入,可以直接将值设置到        
		//BeanUtils.copyProperties(resource,target);  
		//将resource的值映射到target,内省机制,因此属性名必须对应    
	}        
	@Test    
	public void UpdateTest(){        
		MongoTemplate mongoTemplate = new MongoTemplate();                
		//修改stu_name="三驴"且age!=18的文档为stu_name="三驴弟弟",age=18        
		Query query=Query.query(Criteria.where("stu_name").is("三驴").and("age").ne(18));        
		Update update = new Update().set("stu_name", "三驴弟弟").set("age", 18);        
		UpdateResult updateResult = mongoTemplate.updateFirst(query, update, Student.class);    
	}        
	@Test    
	public void DeleteTest(){        
		MongoTemplate mongoTemplate = new MongoTemplate();                
		//删除所有grade_id=3        
		Query query = Query.query(Criteria.where("grade_id").is(3));        
		DeleteResult deleteResult = mongoTemplate.remove(query, Student.class);        
		//删除全部        
		DeleteResult deleteResult = mongoTemplate.remove(new Query(), Student.class);        
		//删除所有 age=4 -> 表 student        
		Query query = Query.query(Criteria.where("age").is(4));        
		DeleteResult deleteResult = mongoTemplate.remove(query, "student");    
	}        
	@Test    
	public void SelectTest(){        
		MongoTemplate mongoTemplate = new MongoTemplate();                
		//查询对应Document        
		mongoTemplate.findAll(Document.class, "student");                
		//查询所有的数据        
		mongoTemplate.findAll(Student.class);        
		//查询stu_name="三驴"        
		Query query=Query.query(Criteria.where("stu_name").is("三驴"));        
		//查询age>18        
		Query query=Query.query(Criteria.where("age").gt(18));        
		mongoTemplate.find(query,Student.class);        
		//查询stu_name="三驴" and age>16        
		Query query=Query.query(Criteria.where("stu_name").is("三驴").and("age").gt(16));   
		mongoTemplate.find(query,Student.class);        
		//查询stu_name like '%牛%'        
		Query query = Query.query(Criteria.where("stu_name").regex("牛"));        
		mongoTemplate.find(query, Student.class);        
		//查询stu_name like '五%'        
		Query query = Query.query(Criteria.where("stu_name").regex("^五"));        
		mongoTemplate.find(query, Student.class);        
		//查询age>15 并且按照age 降序        
		Query query = Query.query(Criteria.where("age").gt(15)).with(new Sort(Sort.Direction.DESC, "age"));        mongoTemplate.find(query,Student.class);                
		//查询排序并分页        
		Query query=new Query();        
		query.with(new Sort(Sort.Direction.ASC,"age"));//按照age升序        
		query.with(new PageRequest(1,3));
		//page 0第一页 1第二页 -> 3每页三条记录       
		mongoTemplate.find(query,Student.class);    
	 }   
 }

3、分页查询

MongoDB的分页较原始,其通过传参给PageImpl(data当前页数据,pageable分页规则,totalCount分页数据总条数)实现分页,PageImpl是实现Page的一个类

public Page<StrategyComment> queryPage(StrategyQuery qo) {    
	Query query = new Query();    
	query.addCriteria(Criteria.where("strategyId").is(qo.getStrategyId()));    
	//分页数据总量totalCount    
	long totalCount = template.count(query, StrategyComment.class);    
	PageRequest pageable = PageRequest.of(qo.getCurrentPage() - 1, qo.getPageSize());  //分页规则    
	query.with(pageable);  
	//分页条件是strategyId,以及从第currentpage每页pagesize的数据    
	List<StrategyComment> data = template.find(query, StrategyComment.class);    
	return new PageImpl<>(data,pageable,totalCount);
}

4、注意事项

由于每个类都是继承自Object类的,而@Document的类(即MongoDB的类)会反射获取所有属性,因此会继承Object的_class属性,而在save操作的时候会把值设置到对应的class属性,所以需要在配置类中配置,去除class属性(class有下划线的),其实也可以每次在save之前setClass为null

启动类中的配置

//mongodb 去除_class属性
@Bean
public MappingMongoConverter mappingMongoConverter(MongoDatabaseFactory factory, 
							MongoMappingContext context, BeanFactory beanFactory) {
	 DbRefResolver dbRefResolver = new DefaultDbRefResolver(factory);
	 MappingMongoConverter mappingConverter = new MappingMongoConverter(dbRefResolver, context);    
	 try {   
	     mappingConverter.setCustomConversions(beanFactory.getBean(CustomConversions.class));       
	 } catch (NoSuchBeanDefinitionException ignore) {   
	 	ignore.printStackTrace();
	 } // Don't save _class to mongo    
     mappingConverter.setTypeMapper(new DefaultMongoTypeMapper(null));    
     return mappingConverter;
 }
  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

肥肥肥柯

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值