Mongodb安装到SpringBoot应用

438 阅读8分钟

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 : (可选)如果设为 true1,则只删除一个文档,如果不设置该参数,或使用默认值 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);
    }
}