1.MongoDB在Linux的安装
1.1 压缩包解压
tar -zxvf MongoDB-linux-x86_64-4.1.3.tgz
1.2 默认启动方式
cd /usr/local/mongodb/mongodb-linux-x86_64-4.1.3/bin
./mongod
第一次启动会报 exception in initAndListen: NonExistentPath: Data directory /data/db not found.
1.3 创建配置文件
配置文件需要自己创建
vi mongo.conf
dbpath=/data/mongo/ //数据库目录,默认/data/db
port=27017 //监听的端口,默认27017
bind_ip=0.0.0.0 //监听IP地址,默认全部可以访问
fork=true //是否已后台启动的方式登陆
logpath = /data/mongo/MongoDB.log //日志路径
logappend = true //是否追加日志
auth=false //是开启用户密码登陆
esc键,退出编辑状态 冒号键 wq!
1.4 创建 dbpath并启动
mkdir -p 可以创建多个
mkdir -p /data/mongo
./bin/mongod -f mongo.conf
1.5 查看启动状态
ps -ef|grep mongo
2.MongoDB命令
2.1 MongoDB基本操作
查看数据库
show dbs;
切换数据库 如果没有对应的数据库则创建
use 数据库名;
创建集合
db.createCollection("集合名")
查看集合
show tables;
show collections;
查看集合数据
db.getCollection("xxx").find()
db.xxx.find()
删除集合
db.集合名.drop();
删除当前数据库
db.dropDatabase();
2.2 MongoDB集合数据操作
2.2.1 数据添加
(1)单条新增
db.user.insert({
name:'张三',
birthday:new ISODate('1999-12-12'),
salary:2500,
city:'bj'
}
)
(2)多条新增
db.user.insert([{
name:'张三',
birthday:new ISODate('1999-12-12'),
salary:2500,
city:'bj'
},{
name:'李四',
birthday:new ISODate('1998-12-12'),
salary:3500,
city:'bj'
},{
name:'王麻子',
birthday:new ISODate('1995-02-24'),
salary:5500,
city:'cq'
}
])
2.2.2 数据查询
(1)比较条件查询
| 操作 | 条件格式 |
|---|---|
| 等于 | {key:value} |
| 大于 | {key:{$gt:value}} |
| 小于 | {key:{$lt:value}} |
| 大于等于 | {key:{$gte:value}} |
| 小于等于 | {key:{$lte:value}} |
| 不等于 | {key:{$ne:value}} |
- 查询名称为张三的数据
db.user.find({name:'张三'})
db.user.find({name:{$eq:'张三'}})
- 查询工资大于5000的人
db.user.find({salary:{$gt:5000}})
(2)逻辑条件查询
and 条件
MongoDB 的 find() 方法可以传入多个键(key),每个键(key)以逗号隔开,即常规 SQL 的AND条件
db.集合名.find({key1:value1, key2:value2}).pretty()
or 条件db.集合名.find({$or:[{key1:value1}, {key2:value2}]}).pretty()
not 条件 db.集合名.find({key:{$not:{$操作符:value}}).pretty()
pretty()的作用是打印查询出的数据格式化
- 查询工资为2500 城市为bj的人
db.user.find({salary:2500,city:'bj'})
- 查询工资为2500或3500的人
db.user.find({ $or:[{salary:2500},{salary:3500}]})
(3) 分页查询
db.集合名.find({条件}).sort({排序字段:排序方式})).skip(跳过的行数).limit(一页显示多少数据)
- 查询bj按照工资升序第一页的两条数据
db.user.find({city:'bj'}).sort({salary:1}).skip(0).limit(2)
(4) 限定返回字段
- db.user.find({},{_id:0}) _id字段不返回 其它都返回
- db.user.find({},{_id:1}) 只返回_id
- db.user.find({},{name:0}) name字段不返回 其它都返回
- db.user.find({},{name:1}) 只返回name和_id
2.2.3 数据更新
db.user.update(query, update, options)
query:查询条件
update:操作
$set :设置字段值
$unset :删除指定字段
$inc:对修改的值进行自增
options :可选的配置
upsert: <boolean>, 如果不存在update的记录,是否插入objNew,true为插入,默认 是false,不插入。
multi: <boolean>, 默认是false,只更新找到的第一条记录,如果这个参数为true,就把按条件查 出来多条记录全部更新。
writeConcern: <document> 用来指定mongod对写操作的回执行为比如写的行为是否需要确认。
- 修改张三的工资
db.user.update({name:'张三'}, {$set:{salary:3000}})
- 修改张三2的信息,如果没有张三2则新增一条
db.user.update({name:'张三2'}, {$set:{salary:2000,city:'bj'}},{upsert:true})
- 将城市为bj的记录 工资全部修改为2000
db.user.update({city:'bj'}, {$set:{salary:2000}},{multi:true})
- 将张三的工资新增1000
db.user.update({name:'张三'}, {$inc:{salary:1000}})
- 将张三的生日字段删除
db.user.update({name:'张三'}, {$unset:{birthday:''}})
2.2.4 数据删除
db.collection.remove(
<query>,
{
justOne: <boolean>,
writeConcern: <document>
} )
参数说明:
query :(可选)删除的文档的条件。
justOne : (可选)如果设为 true 或 1,则只删除一个文档,如果不设置该参数,或使用默认值 false,则删除所有匹配条件的文档。
writeConcern :(可选)用来指定mongod对写操作的回执行为。
2.3 MongoDB 聚合操作
2.3.1 单目聚合操作
db.user.find().count()
db.user.count()
db.user.distinct("city")
2.3.2 聚合管道
MongoDB的聚合管道将MongoDB文档在一个管道处理完毕后将结果传递给下一个管道处理。管道操作 是可以重复的。
聚合框架中常用的几个操作
| 操作 | 描述 |
|---|---|
| $group | 将集合中的文档分组,可用于统计结果。 |
| $project | 修改输入文档的结构。可以用来重命名、增加或删除域,也可以用于创建计算结果以及嵌套文档。 |
| $match | 用于过滤数据,只输出符合条件的文档。$match使用MongoDB的标准查询操作。 |
| $limit | 用来限制MongoDB聚合管道返回的文档数。 |
| $skip | 在聚合管道中跳过指定数量的文档,并返回余下的文档。 |
| $sort | 将输入文档排序后输出。 |
| $geoNear | 输出接近某一地理位置的有序文档。 |
| 表达式 | 描述 |
|---|---|
| $sum | 计算总和 |
| $avg | 计算平均值 |
| $min | 获取集合中所有文档对应值得最小值 |
| $max | 获取集合中所有文档对应值得最大值 |
| $push | 在结果文档中插入值到一个数组中 |
| $addToSet | 在结果文档中插入值到一个数组中,但数据不重复 |
| $first | 根据资源文档的排序获取第一个文档数据 |
| $last | 根据资源文档的排序获取最后一个文档数据 |
- 按照city进行分组,统计每个city出现的次数
db.user.aggregate([{$group:{_id:"$city",city_count:{$sum:1}}}])
或
db.user.aggregate({$group:{_id:"$city",city_count:{$sum:1}}})
- 按照city进行分组,统计每个city的平均工资
db.user.aggregate({$group:{_id:"$city",avg_salary:{$avg:"$salary"}}})
- $project重命名
db.user.aggregate([
{$group:{_id:"$city",avg_salary:{$avg:"$salary"}}},
{$project : {city: "$city", saly : "$avg_salary"}}
])
- $match 过滤数据 只输出大于2500
db.user.aggregate([
{$group:{_id:"$city",avg_salary:{$avg:"$salary"}}},
{$project : {city: "$city", saly : "$avg_salary"}},
{$match:{saly:{$gt:2500}}}
])
2.3.3 MapReduce 编程模型
Pipeline查询速度快于MapReduce,但是MapReduce的强大之处在于能够在多台Server上并行执行复 杂的聚合逻辑。MongoDB不允许Pipeline的单个聚合操作占用过多的系统内存,如果一个聚合操作消 耗20%以上的内存,那么MongoDB直接停止操作,并向客户端输出错误消息。 MapReduce是一种计算模型,简单的说就是将大批量的工作(数据)分解(MAP)执行,然后再将结 果合并成最终结果(REDUCE)。
db.user.mapReduce(
//map 函数
function(){
emit(this.city,this.salary)
},
//reduce 函数
function(key,values){
return Array.avg(values)
},
{
out:'cityAvgSal',
query:{salary:{$gt: 3000}},
}
)
//查询执行结果
db.cityAvgSal.find();
使用 MapReduce 要实现两个函数 Map 函数和 Reduce 函数,Map 函数调用 emit(key, value), 遍历 collection 中所有的记录, 将 key 与 value 传递给 Reduce 函数进行处理
参数说明:
- map:JavaScript 函数, 负责将每一个输入文档转换为零或多个文档,生成键值对序列,作为reduce 函数参数
- reduce:JavaScript 函数,对map操作的输出做合并的化简的操作(将key-value变成keyvalues,也就是把values数组变成一个单一的值value)
- out:统计结果存放集合
- query: 一个筛选条件,只有满足条件的文档才会调用map函数。
- sort: 和limit结合的sort排序参数(也是在发往map函数前给文档排序),可以优化分组机制
- limit: 发往map函数的文档数量的上限(要是没有limit,单独使用sort的用处不大)
- finalize:可以对reduce输出结果再一次修改
- verbose:是否包括结果信息中的时间信息,默认为fasle
3.MongoDB索引Index
3.1 索引类型
3.1.1 单键索引 (Single Field)
db.user.createIndex(keys, options)
单个例上创建索引:
db.集合名.createIndex({"字段名":排序方式})
//为name字段创建索引 1为正序
db.user.createIndex({"name":1})
db.user.getIndexes()
删除索引:
db.users.dropIndex({name:1})
db.COLLECTION_NAME.dropIndex("INDEX-NAME")
db.COLLECTION_NAME.dropIndexes()
- 特殊的单键索引 过期索引 TTL ( Time To Live)
TTL索引是MongoDB中一种特殊的索引, 可以支持文档在一定时间之后自动过期删除,目前TTL索引 只能在单字段上建立,并且字段类型必须是日期类型。
db.集合名.createIndex({"日期字段":排序方式}, {expireAfterSeconds: 秒数})
创建索引20s后,有birthday字段的文档会自动删除
db.user.createIndex({"birthday":1}, {expireAfterSeconds:20})
3.1.2 复合索引(Compound Index)
制作复合索引时要注意的重要事项包括:字段顺序与索引方向。
db.集合名.createIndex( { "字段名1" : 排序方式, "字段名2" : 排序方式 } )
3.1.3 多键索引(Multikey indexes)
针对属性包含数组数据的情况,MongoDB支持针对数组中每一个element创建索引,Multikey indexes支持strings,numbers和nested documents
3.1.4 地理空间索引(Geospatial Index)
针对地理空间坐标数据创建索引。
- 2dsphere索引,用于存储和查找球面上的点
- 2d索引,用于存储和查找平面上的点
GeoJSON是一种对各种地理数据结构进行编码的格式。
{type:"Point",coordinates:[106.320765,29.594854]}
type成员的值是下面字符串之一: "Point", "MultiPoint", "LineString", "MultiLineString", "Polygon", "MultiPolygon", 或者"GeometryCollection"。
GeoJSON几何对象必须由一个名字为"coordinates"的成员。coordinates成员的值总是数组。这个数组里的元素的结构由几何类型来确定。
(1)插入数据
db.company.insert([{
loc:{type:"Point",coordinates:[106.320765,29.594854]},
name:'曦城蓝湾'
},{
loc:{type:"Point",coordinates:[106.322175,29.596256]},
name:'西湖幼儿圆'
},{
loc:{type:"Point",coordinates:[106.240726,29.584199]},
name:'璧山体育馆'
},{
loc:{type:"Point",coordinates:[106.48104,29.530853]},
name:'石新路'
},{
loc:{type:"Point",coordinates:[106.319417,29.59191]},
name:'国际城'
},{
loc:{type:"Point",coordinates:[106.315384,29.587426]},
name:'协信城'
},{
loc:{type:"Point",coordinates:[106.442809,29.507721]},
name:'重庆西站'
}])
(2)创建索引
db.company.createIndex({loc:"2dsphere"})
(3) 查询曦城蓝湾方圆5公里
db.company.find({
loc:{
$geoWithin: {
$center:[[106.320765,29.594854],0.05]
}
}
})
(4) 查询曦城蓝湾方圆周围最近的3个点
db.company.aggregate([
{
$geoNear:{
near:{type:"Point",coordinates:[106.320765,29.594854]},
key:"loc",
distanceField:"dist.calculated"
}
},
{$limit:3}
])
3.1.5 全文索引(Text Index)
MongoDB提供了针对string内容的文本查询,Text Index支持任意属性值为string或string数组元素的 索引查询。注意:一个集合仅支持最多一个Text Index,中文分词不理想 推荐ES。
db.test.insert({id:1,name:'test1',city:'bj',description:'one world one dream in bj'})
db.test.insert({id:2,name:'test2',city:'nj',description:'two world two dream in nj'})
db.test.insert({id:3,name:'test3',city:'dj',description:'three world three dream in dj'})
db.test.createIndex({description:'text'})
db.test.find({$text:{$search:'world'}})
3.1.6 哈希索引(Hashed Index)
针对属性的哈希值进行索引查询,当要使用Hashed index时,MongoDB能够自动的计算hash值,无 需程序计算hash值。注:hash index仅支持等于查询,不支持范围查询。
db.集合.createIndex({"字段": "hashed"})
3.2 索引和explain 分析
3.2.1 explain 分析
- 插入100万条数据, 建议在Linux环境下
for(var i=0;i<1000000;i++){
db.lg_resume.insert({id:i,name:'test'+i,salary:(Math.random()*20000).toFixed(2)})
}
explain()也接收不同的参数,通过设置不同参数我们可以查看更详细的查询计划。
- queryPlanner:queryPlanner是默认参数,具体执行计划信息参考下面的表格。
- executionStats:executionStats会返回执行计划的一些统计信息(有些版本中和allPlansExecution等同)。
- allPlansExecution:allPlansExecution用来获取所有执行计划,结果参数基本与上文相同。
(1) 执行 db.lg_resume.find({name:"test11011"}).explain()
{
"queryPlanner": {
"plannerVersion": NumberInt("1"), //查询计划版本
"namespace": "lagou.lg_resume",//要查询的集合(该值返回的是该query所查询的表)数据库.集合
"indexFilterSet": false,//针对该query是否有indexFilter
"parsedQuery": {//查询条件
"name": {
"$eq": "test11011"
}
},
"queryHash": "01AEE5EC",
"winningPlan": { //被选中的执行计划
"stage": "COLLSCAN", //被选中执行计划的stage(查询方式)
"filter": { //过滤条件
"name": {
"$eq": "test11011"
}
},
"direction": "forward" //此query的查询顺序
},
"rejectedPlans": [ ] //被拒绝的执行计划的详细返回,其中具体信息与winningPlan的返回中意义相同
},
"serverInfo": { //MongoDB服务器信息
"host": "VM-8-15-centos",
"port": NumberInt("27017"),
"version": "4.1.3",
"gitVersion": "7c13a75b928ace3f65c9553352689dc0a6d0ca83"
},
"ok": 1
}
winningPlan.stage
被选中执行计划的stage(查询方式),常见的有:COLLSCAN/全表 扫描:(应该知道就是CollectionScan,就是所谓的“集合扫描”, 和mysql中table scan/heap scan类似,这个就是所谓的性能最烂 最无奈的由来)、IXSCAN/索引扫描:(是IndexScan,这就说明 我们已经命中索引了)、FETCH/根据索引去检索文档、 SHARD_MERGE/合并分片结果、IDHACK/针对_id进行查询等
winningPlan.direction
此query的查询顺序,此处是forward,如果用了.sort({字段:-1}) 将显示backward。
(2) 执行 db.lg_resume.find({name:"test11011"}).explain("executionStats")
// 1
{
"queryPlanner": {
"plannerVersion": NumberInt("1"),
"namespace": "lagou.lg_resume",
"indexFilterSet": false,
"parsedQuery": {
"name": {
"$eq": "test11011"
}
},
"queryHash": "01AEE5EC",
"winningPlan": {
"stage": "COLLSCAN",
"filter": {
"name": {
"$eq": "test11011"
}
},
"direction": "forward"
},
"rejectedPlans": [ ]
},
"executionStats": {
"executionSuccess": true, //是否执行成功
"nReturned": NumberInt("1"), //返回的文档数
"executionTimeMillis": NumberInt("355"), //执行耗时
"totalKeysExamined": NumberInt("0"), //索引扫描次数
"totalDocsExamined": NumberInt("1000000"), //文档扫描次数
"executionStages": { //描述执行的状态
"stage": "COLLSCAN", //扫描方式
"filter": {
"name": {
"$eq": "test11011"
}
},
"nReturned": NumberInt("1"), //查询结果数量
"executionTimeMillisEstimate": NumberInt("298"), //检索document获得数据的时间
"works": NumberInt("1000002"),//工作单元数,一个查询会分解成小的工作单元
"advanced": NumberInt("1"), //优先返回的结果数
"needTime": NumberInt("1000000"),
"needYield": NumberInt("0"),
"saveState": NumberInt("7824"),
"restoreState": NumberInt("7824"),
"isEOF": NumberInt("1"),
"direction": "forward",
"docsExamined": NumberInt("1000000")//文档检查数目,与totalDocsExamined一致。检查了总共的document个数,而从返回上面的nReturned数量
}
},
"serverInfo": {
"host": "VM-8-15-centos",
"port": NumberInt("27017"),
"version": "4.1.3",
"gitVersion": "7c13a75b928ace3f65c9553352689dc0a6d0ca83"
},
"ok": 1
}
(3)id字段分析
db.lg_resume.find({id:{$gt:222333}}).explain("executionStats")
//去掉了不分析的字段
{
"queryPlanner": {
"winningPlan": {
"stage": "COLLSCAN",
},
},
"executionStats": {
"nReturned": NumberInt("777666"),
"executionTimeMillis": NumberInt("346"),
"totalKeysExamined": NumberInt("0"),
"totalDocsExamined": NumberInt("1000000"),
"executionStages": {
"stage": "COLLSCAN",
"nReturned": NumberInt("777666"),
"executionTimeMillisEstimate": NumberInt("209"),
"
}
},
}
加上索引 db.lg_resume.createIndex({id:1})
// 1
{
"queryPlanner": {
"winningPlan": {
"stage": "FETCH",
"inputStage": { //用来描述子stage,并且为其父stage提供文档和索引关键字。
"stage": "IXSCAN",
"keyPattern": {
"id": 1
},
"indexName": "id_1",
"isMultiKey": false,
"multiKeyPaths": {
"id": [ ]
},
}
},
},
"executionStats": {
"nReturned": NumberInt("777666"),
"executionTimeMillis": NumberInt("766"),
"totalKeysExamined": NumberInt("777666"),
"totalDocsExamined": NumberInt("777666"),
"executionStages": {
"stage": "FETCH",
"nReturned": NumberInt("777666"),
"executionTimeMillisEstimate": NumberInt("715"),
}
},
}
3.2.2 executionStats返回逐层分析
第一层:
executionTimeMillis最为直观explain返回值是executionTimeMillis值,指的是这条语句的执 行时间,这个值当然是希望越少越好。
其中有3个executionTimeMillis,分别是:
executionStats.executionTimeMillis 该query的整体查询时间。
executionStats.executionStages.executionTimeMillisEstimate 该查询检索document获得数据的时 间。
executionStats.executionStages.inputStage.executionTimeMillisEstimate 该查询扫描文档 index 所用时间。
第二层:
index与document扫描数与查询返回条目数
这个主要讨论3个返回项
nReturned、totalKeysExamined、totalDocsExamined,分别代表该条查询返回的条目、索引扫描条目、文档扫描 条目。 这些都是直观地影响到executionTimeMillis,我们需要扫描的越少速度越快。 对于一个查询,
我们最理想的状态是:nReturned=totalKeysExamined=totalDocsExamined
第三层:
stage状态分析
类型列举如下: COLLSCAN:全表扫描
IXSCAN:索引扫描
FETCH:根据索引去检索指定document
SHARD_MERGE:将各个分片返回数据进行merge
SORT:表明在内存中进行了排序
LIMIT:使用limit限制返回数
SKIP:使用skip进行跳过
IDHACK:针对_id进行查询
SHARDING_FILTER:通过mongos对分片数据进行查询
COUNT:利用db.coll.explain().count()之类进行count运算
TEXT:使用全文索引进行查询时候的stage返回
PROJECTION:限定返回字段时候stage的返回
对于普通查询,我希望看到stage的组合(查询的时候尽可能用上索引):
Fetch+IDHACK
Fetch+IXSCAN
Limit+(Fetch+IXSCAN)
PROJECTION+IXSCAN
SHARDING_FITER+IXSCAN
不希望看到包含如下的stage: COLLSCAN(全表扫描)
SORT(使用sort但是无index)
COUNT 不使用index进行count)
3.2.3 慢查询分析
1.开启内置的查询分析器,记录读写操作效率
db.setProfilingLevel(n,m),n的取值可选0,1,2
0表示不记录
1表示记录慢速操作,如果值为1,m必须赋值单位为ms,用于定义慢速查询时间的阈值
2表示记录所有的读写操作
2.查询监控结果
db.system.profile.find().sort({millis:-1}).limit(3)
3.分析慢速查询
应用程序设计不合理、不正确的数据模型、硬件配置问题,缺少索引等
4.解读explain结果 确定是否缺少索引
4. MongoDB 应用实战
4.1 Java 访问MongoDB
maven 依赖
<dependency>
<groupId>org.mongodb</groupId>
<artifactId>mongo-java-driver</artifactId>
<version>3.10.1</version>
</dependency>
package com.lagou.test;
import com.mongodb.MongoClient;
import com.mongodb.client.FindIterable;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoDatabase;
import com.mongodb.client.model.Filters;
import org.bson.Document;
/**
* @Author 振帅
* @Date 2021/07/08 23:08
*/
public class DocumentTest {
public static void main(String[] args) {
MongoClient mongoClient = new MongoClient("123.207.31.211",27017);
//获取数据库对象
MongoDatabase database = mongoClient.getDatabase("lagou");
//获取集合对象
MongoCollection<Document> collection = database.getCollection("user");
//新增
Document user = Document.parse("{name:'test',birthday:new ISODate('2002-02-11'),salary:2000,city:'cq'}");
// collection.insertOne(user);
//查询
Document sortDocument = new Document();
//工资倒序
sortDocument.append("salary",-1);
//过滤 方式1
//FindIterable<Document> findIterable = collection.find(Document.parse("{salary:{$gt:2000}}")).sort(sortDocument);
//过滤 方式2 使用 Filters
FindIterable<Document> findIterable = collection.find(Filters.gt("salary",2000)).sort(sortDocument);
for (Document document : findIterable) {
System.out.println(document);
}
mongoClient.close();
}
}
4.2 Spring 访问MongoDB
4.2.1 基于maven新建工程 导入依赖的包
根据依赖关系,引入此包后 不用引用spring相关包
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-mongodb</artifactId>
<version>2.0.9.RELEASE</version>
</dependency>
4.2.2 applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mongo="http://www.springframework.org/schema/data/mongo"
xsi:schemaLocation=" http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/data/mongo
http://www.springframework.org/schema/data/mongo/spring-mongo.xsd
">
<!-- 开启组件扫描 -->
<context:component-scan base-package="com.lagou"/>
<!-- 构建MongoDb工厂对象 -->
<mongo:db-factory id="mongoDbFactory" client-uri="mongodb://123.207.31.211:27017/lagou" />
<!-- 构建 MongoTemplate 类型的对象 -->
<bean id="mongoTemplate" class="org.springframework.data.mongodb.core.MongoTemplate">
<constructor-arg ref="mongoDbFactory"/>
</bean>
</beans>
4.2.3 User.java
- id字段与_id 对应
public class User {
private String id;
private String name;
private Date birthday;
private Double salary;
//省略get set方法
}
4.2.4 UserDao.java
package com.lagou.dao;
import com.lagou.bean.User;
/**
* @author 振帅
* Created on 2021/07/12 10:24
*/
public interface UserDao {
//新增
void insertUser(User user);
//查询
User findByName(String name);
}
4.2.5 UserDaoImpl.java
package com.lagou.dao;
import com.lagou.bean.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.stereotype.Repository;
/**
* @author 振帅
* Created on 2021/07/12 10:29
*/
@Repository("userDao")
public class UserDaqImpl implements UserDao {
@Autowired
private MongoTemplate mongoTemplate;
@Override
public void insertUser(User user) {
//mongoTemplate.insert(user);
//插入指定集合 没有就会自动创建集合
mongoTemplate.insert(user,"users");
}
@Override
public User findByName(String name) {
Query query = new Query();
query.addCriteria(Criteria.where("name").is(name));
//不指定集合名称 会自动去找 user集合
User user = mongoTemplate.findOne(query, User.class,"users");
return user;
}
}
4.2.6 测试类
package com.lagou;
import com.lagou.bean.User;
import com.lagou.dao.UserDao;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* @author 振帅
* Created on 2021/07/12 10:31
*/
public class MongoTemplateMain {
public static void main(String[] args) {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
UserDao userDao = context.getBean("userDao",UserDao.class);
User user = new User();
user.setName("test");
Date date = null;
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
try {
date = simpleDateFormat.parse("2001-12-12 11:21:11");
} catch (ParseException e) {
e.printStackTrace();
}
user.setBirthday(date);
user.setSalary(4500d);
userDao.insertUser(user);
User test = userDao.findByName("test");
System.out.println(test);
}
}
4.4 SpringBoot 访问MongoDB
4.4.1 MongoTemplate 的方式
第1步:基于maven新建springboot工程
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb</artifactId>
<version>2.2.2.RELEASE</version>
</dependency>
第2步: 配置文件application.properties
spring.data.mongodb.host=123.207.31.211
spring.data.mongodb.port=27017
spring.data.mongodb.database=lagou
spring.data.cassandra.read-timeout=10000
剩下的和spring的一样
4.4.2 MongoRepository 的方式
1、2步同上
第3步:编写实体类 并在实体类上打@Document(“集合名”)
@Document("users")
public class User {
private String id;
private String name;
private Date birthday;
private Double salary;
}
第4步:编写 Repository 接口 继承 MongoRepository
方法具体参考:docs.spring.io/spring-data… ethods.query-creation
如果内置方法不够用 就自己定义 如:定义find|read|get 等开头的方法进行查询
package com.lagou.repository;
import com.lagou.bean.User;
import org.springframework.data.mongodb.repository.MongoRepository;
/**
* @author 振帅
* Created on 2021/07/12 16:00
*/
public interface UserRepositroy extends MongoRepository<User,String> {
User findUsersByNameAndSalaryEquals(String name,Double salary);
User findUsersByNameEquals(String name);
}
第5步: 从Spring容器中获取Repository对象 进行测试
@SpringBootApplication
public class Application {
public static void main(String[] args) {
ApplicationContext context = SpringApplication.run(Application.class,args);
UserRepositroy userRepositroy = context.getBean(UserRepositroy.class);
User user = userRepositroy.findUsersByNameAndSalaryEquals("test", 4600d);
System.out.println(user);
}
}