1. 程式人生 > 資料庫 >MongoDB快速入門-通過docker安裝MongoDB,MongoDB的基本操作,索引,執行計劃,SpringBoot整合MongoDB,MongoDB認證

MongoDB快速入門-通過docker安裝MongoDB,MongoDB的基本操作,索引,執行計劃,SpringBoot整合MongoDB,MongoDB認證

MongoDB

1、MongoDB入門

1.1、MongoDB簡介

MongoDB是一個基於分散式檔案儲存的資料庫。由C++語言編寫。旨在為WEB應用提供可擴充套件的高效能資料儲存解決方案。

MongoDB是一個介於關係資料庫和非關係資料庫之間的產品,是非關係資料庫當中功能最豐富,最像關係資料庫的,它支援的資料結構非常鬆散,是類似json的bson格式,因此可以儲存比較複雜的資料型別。

MongoDB最大的特點是它支援的查詢語言非常強大,其語法有點類似於面向物件的查詢語言,幾乎可以實現類似關係資料庫單表查詢的絕大部分功能,而且還支援對資料建立索引。

官網:https://www.mongodb.com

1.2、通過docker安裝MongoDB

#拉取映象
docker pull mongo:4.0.3

#建立容器
docker create --name mongodb -p 27017:27017 -v /data/mongodb:/data/db mongo:4.0.3

#啟動容器
docker start mongodb

#進入容器
docker exec -it mongodb /bin/bash

#使用MongoDB客戶端進行操作
mongo
> show dbs  #查詢所有的資料庫

admin   0.000GB
config  0.000GB
local   0.000GB

1.3、MongoDB基本操作

1.3.1、基本概念

為了更好的理解,下面與SQL中的概念進行對比:

SQL術語/概念MongoDB術語/概念解釋/說明
databasedatabase資料庫
tablecollection資料庫表/集合
rowdocument資料記錄行/文件
columnfield資料欄位/域
indexindex索引
table joins表連線,MongoDB不支援
primary keyprimary key主鍵,MongoDB自動將_id欄位設定為主鍵

1.3.2、資料庫以及表的操作

#檢視所有的資料庫
> show dbs
admin   0.000GB
config  0.000GB
local   0.000GB

#通過use關鍵字切換資料庫
> use admin
switched to db admin

#建立資料庫
#說明:在MongoDB中,資料庫是自動建立的,通過use切換到新資料庫中,進行插入資料即可自動建立資料庫
> use testdb
switched to db testdb
> show dbs #並沒有建立資料庫
admin   0.000GB
config  0.000GB
local   0.000GB
> db.user.insert({id:1,name:'zhangsan'})  #插入資料
WriteResult({ "nInserted" : 1 })
> show dbs
admin   0.000GB
config  0.000GB
local   0.000GB
testdb  0.000GB #資料庫自動建立

#查看錶
> show tables
user
> show collections
user
> 

#刪除集合(表)
> db.user.drop()
true  #如果成功刪除選定集合,則 drop() 方法返回 true,否則返回 false。

#刪除資料庫
> use testdb #先切換到要刪除的資料中
switched to db testdb
> db.dropDatabase()  #刪除資料庫
{ "dropped" : "testdb", "ok" : 1 }
> show dbs
admin   0.000GB
config  0.000GB
local   0.000GB

1.3.3、新增資料

在MongoDB中,儲存的文件結構是一種類似於json的結構,稱之為bson(全稱為:Binary JSON)。

#插入資料
#語法:db.COLLECTION_NAME.insert(document)

> db.user.insert({id:1,username:'zhangsan',age:20})
WriteResult({ "nInserted" : 1 })
> db.user.save({id:2,username:'lisi',age:25})
WriteResult({ "nInserted" : 1 })
> db.user.find()  #查詢資料
{ "_id" : ObjectId("5c08c0024b318926e0c1f6dc"), "id" : 1, "username" : "zhangsan", "age" : 20 }
{ "_id" : ObjectId("5c08c0134b318926e0c1f6dd"), "id" : 2, "username" : "lisi", "age" : 25 }

1.3.4、更新資料

update() 方法用於更新已存在的文件。語法格式如下:

db.collection.update(
   <query>,
   <update>,
   [
     upsert: <boolean>,
     multi: <boolean>,
     writeConcern: <document>
   ]
)

引數說明:

  • query : update的查詢條件,類似sql update查詢內where後面的。
  • update : update的物件和一些更新的操作符(如 , , ,inc…)等,也可以理解為sql update查詢內set後面的
  • upsert : 可選,這個引數的意思是,如果不存在update的記錄,是否插入objNew,true為插入,預設是false,不插入。
  • multi : 可選,mongodb 預設是false,只更新找到的第一條記錄,如果這個引數為true,就把按條件查出來多條記錄全部更新。
  • writeConcern :可選,丟擲異常的級別。
> db.user.find()
{ "_id" : ObjectId("5c08c0024b318926e0c1f6dc"), "id" : 1, "username" : "zhangsan", "age" : 20 }
{ "_id" : ObjectId("5c08c0134b318926e0c1f6dd"), "id" : 2, "username" : "lisi", "age" : 25 }
# 不加$set修改器為文件替換  db.user.update({id:1},{age:22})
> db.user.update({id:1},{$set:{age:22}}) #更新資料

WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })

> db.user.find()
{ "_id" : ObjectId("5c08c0024b318926e0c1f6dc"), "id" : 1, "username" : "zhangsan", "age" : 22 }
{ "_id" : ObjectId("5c08c0134b318926e0c1f6dd"), "id" : 2, "username" : "lisi", "age" : 25 }

#注意:如果這樣寫,會刪除掉其他的欄位
> db.user.update({id:1},{age:25})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
> db.user.find()
{ "_id" : ObjectId("5c08c0024b318926e0c1f6dc"), "age" : 25 }
{ "_id" : ObjectId("5c08c0134b318926e0c1f6dd"), "id" : 2, "username" : "lisi", "age" : 25 }

#更新不存在的欄位,會新增欄位
> db.user.update({id:2},{$set:{sex:1}}) #更新資料
> db.user.find()
{ "_id" : ObjectId("5c08c0024b318926e0c1f6dc"), "age" : 25 }
{ "_id" : ObjectId("5c08c0134b318926e0c1f6dd"), "id" : 2, "username" : "lisi", "age" : 25, "sex" : 1 }

#更新不存在的資料,預設不會新增資料
> db.user.update({id:3},{$set:{sex:1}})
WriteResult({ "nMatched" : 0, "nUpserted" : 0, "nModified" : 0 })
> db.user.find()
{ "_id" : ObjectId("5c08c0024b318926e0c1f6dc"), "age" : 25 }
{ "_id" : ObjectId("5c08c0134b318926e0c1f6dd"), "id" : 2, "username" : "lisi", "age" : 25, "sex" : 1 }

#如果設定第一個引數為true,就是新增資料
> db.user.update({id:3},{$set:{sex:1}},true)
WriteResult({
	"nMatched" : 0,
	"nUpserted" : 1,
	"nModified" : 0,
	"_id" : ObjectId("5c08cb281418d073246bc642")
})
> db.user.find()
{ "_id" : ObjectId("5c08c0024b318926e0c1f6dc"), "age" : 25 }
{ "_id" : ObjectId("5c08c0134b318926e0c1f6dd"), "id" : 2, "username" : "lisi", "age" : 25, "sex" : 1 }
{ "_id" : ObjectId("5c08cb281418d073246bc642"), "id" : 3, "sex" : 1 }

1.3.5、刪除資料

通過remove()方法進行刪除資料,語法如下:

db.collection.remove(
   <query>,
   {
     justOne: <boolean>,
     writeConcern: <document>
   }
)

引數說明:

  • query :(可選)刪除的文件的條件。
  • justOne : (可選)如果設為 true 或 1,則只刪除一個文件,如果不設定該引數,或使用預設值 false,則刪除所有匹配條件的文件。
  • writeConcern :(可選)丟擲異常的級別。

例項:

> db.user.remove({age:25})
WriteResult({ "nRemoved" : 2 })  #刪除了2條資料

#插入4條測試資料
db.user.insert({id:1,username:'zhangsan',age:20})
db.user.insert({id:2,username:'lisi',age:21})
db.user.insert({id:3,username:'wangwu',age:22})
db.user.insert({id:4,username:'zhaoliu',age:22})

> db.user.remove({age:22},true)
WriteResult({ "nRemoved" : 1 })  #刪除了1條資料

#刪除所有資料
> db.user.remove({})

#說明:為了簡化操作,官方推薦使用deleteOne()與deleteMany()進行刪除資料操作。
db.user.deleteOne({id:1})
db.user.deleteMany({})  #刪除所有資料

1.3.6、查詢資料

MongoDB 查詢資料的語法格式如下:

db.user.find([query],[fields])
  • query :可選,使用查詢操作符指定查詢條件
  • fields :可選,使用投影操作符指定返回的鍵。查詢時返回文件中所有鍵值, 只需省略該引數即可(預設省略)。

如果你需要以易讀的方式來讀取資料,可以使用 pretty() 方法,語法格式如下:

>db.user.find().pretty()

pretty() 方法以格式化的方式來顯示所有文件。

條件查詢:

操作格式範例RDBMS中的類似語句
等於{<key>:<value>}db.col.find({"by":"黑馬程式設計師"}).pretty()where by = '黑馬程式設計師'
小於{<key>:{$lt:<value>}}db.col.find({"likes":{$lt:50}}).pretty()where likes < 50
小於或等於{<key>:{$lte:<value>}}db.col.find({"likes":{$lte:50}}).pretty()where likes <= 50
大於{<key>:{$gt:<value>}}db.col.find({"likes":{$gt:50}}).pretty()where likes > 50
大於或等於{<key>:{$gte:<value>}}db.col.find({"likes":{$gte:50}}).pretty()where likes >= 50
不等於{<key>:{$ne:<value>}}db.col.find({"likes":{$ne:50}}).pretty()where likes != 50

例項:

#插入測試資料
db.user.insert({id:1,username:'zhangsan',age:20})
db.user.insert({id:2,username:'lisi',age:21})
db.user.insert({id:3,username:'wangwu',age:22})
db.user.insert({id:4,username:'zhaoliu',age:22})

db.user.find()  #查詢全部資料
db.user.find({},{id:1,username:1})  #只查詢id與username欄位
db.user.find().count()  #查詢資料條數
db.user.find({id:1}) #查詢id為1的資料
db.user.find({age:{$lte:21}}) #查詢小於等於21的資料
db.user.find({age:{$lte:21}, id:{$gte:2}}) #and查詢,age小於等於21並且id大於等於2
db.user.find({$or:[{id:1},{id:2}]}) #查詢id=1 or id=2

#分頁查詢:Skip()跳過幾條,limit()查詢條數
db.user.find().limit(2).skip(1)  #跳過1條資料,查詢2條資料

db.user.find().sort({id:-1}) #按照age倒序排序,-1為倒序,1為正序

1.4、索引

索引通常能夠極大的提高查詢的效率,如果沒有索引,MongoDB在讀取資料時必須掃描集合中的每個檔案並選取那些符合查詢條件的記錄。

這種掃描全集合的查詢效率是非常低的,特別在處理大量的資料時,查詢可以要花費幾十秒甚至幾分鐘,這對網站的效能是非常致命的。

索引是特殊的資料結構,索引儲存在一個易於遍歷讀取的資料集合中,索引是對資料庫表中一列或多列的值進行排序的一種結構

#檢視索引
> db.user.getIndexes()
[
	{
		"v" : 2,
		"key" : {
			"_id" : 1
		},
		"name" : "_id_",
		"ns" : "testdb.user"
	}
]
#說明:1表示升序建立索引,-1表示降序建立索引。
#建立索引
> db.user.createIndex({'age':1})
{
	"createdCollectionAutomatically" : false,
	"numIndexesBefore" : 1,
	"numIndexesAfter" : 2,
	"ok" : 1
}
#刪除索引
db.user.dropIndex("age_1")
#或者,刪除除了_id之外的索引
db.user.dropIndexes()
#建立聯合索引
db.user.createIndex({'age':1, 'id':-1})
#檢視索引大小,單位:位元組
db.user.totalIndexSize()

1.5、執行計劃

MongoDB 查詢分析可以確保我們建議的索引是否有效,是查詢語句效能分析的重要工具。

#插入1000條資料
for(var i=1;i<1000;i++) db.user.insert({id:100+i,username:'name_'+i,age:10+i})
#檢視執行計劃
> db.user.find({age:{$gt:100},id:{$lt:200}}).explain()
{
	"queryPlanner" : {
		"plannerVersion" : 1,
		"namespace" : "testdb.user",
		"indexFilterSet" : false,
		"parsedQuery" : {
			"$and" : [
				{
					"id" : {
						"$lt" : 200
					}
				},
				{
					"age" : {
						"$gt" : 100
					}
				}
			]
		},
		"winningPlan" : {  #最佳執行計劃
			"stage" : "FETCH", #查詢方式,常見的有COLLSCAN/全表掃描、IXSCAN/索引掃描、FETCH/根據索引去檢索文件、SHARD_MERGE/合併分片結果、IDHACK/針對_id進行查詢
			"inputStage" : {
				"stage" : "IXSCAN",
				"keyPattern" : {
					"age" : 1,
					"id" : -1
				},
				"indexName" : "age_1_id_-1",
				"isMultiKey" : false,
				"multiKeyPaths" : {
					"age" : [ ],
					"id" : [ ]
				},
				"isUnique" : false,
				"isSparse" : false,
				"isPartial" : false,
				"indexVersion" : 2,
				"direction" : "forward",
				"indexBounds" : {
					"age" : [
						"(100.0, inf.0]"
					],
					"id" : [
						"(200.0, -inf.0]"
					]
				}
			}
		},
		"rejectedPlans" : [ ]
	},
	"serverInfo" : {
		"host" : "c493d5ff750a",
		"port" : 27017,
		"version" : "4.0.3",
		"gitVersion" : "7ea530946fa7880364d88c8d8b6026bbc9ffa48c"
	},
	"ok" : 1
}
#測試沒有使用索引
> db.user.find({username:'zhangsan'}).explain()
{
	"queryPlanner" : {
		"plannerVersion" : 1,
		"namespace" : "testdb.user",
		"indexFilterSet" : false,
		"parsedQuery" : {
			"username" : {
				"$eq" : "zhangsan"
			}
		},
		"winningPlan" : {
			"stage" : "COLLSCAN",  #全表掃描
			"filter" : {
				"username" : {
					"$eq" : "zhangsan"
				}
			},
			"direction" : "forward"
		},
		"rejectedPlans" : [ ]
	},
	"serverInfo" : {
		"host" : "c493d5ff750a",
		"port" : 27017,
		"version" : "4.0.3",
		"gitVersion" : "7ea530946fa7880364d88c8d8b6026bbc9ffa48c"
	},
	"ok" : 1
}

1.6、UI客戶端工具

Robo 3T是MongoDB的客戶端工具,也可以使用studio-3t,我們可以使用它來操作MongoDB。

2、通過JavaApi操作MongoDB

2.1、建立lichee-mongodb工程

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.lichee.mongodb</groupId>
    <artifactId>lichee-mongodb</artifactId>
    <version>1.0-SNAPSHOT</version>

    <dependencies>
        <dependency>
            <groupId>org.mongodb</groupId>
            <artifactId>mongodb-driver-sync</artifactId>
            <version>3.9.1</version>
        </dependency>
         <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.4</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <!-- java編譯外掛 -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.2</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                    <encoding>UTF-8</encoding>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>

2.2、編寫Demo

該demo中演示了,如何連線到MongoDB,如何選擇資料庫、表,進行查詢的操作。

public class MongoDBDemo {
    public static void main(String[] args) {  
        // 建立連線
        MongoClient mongoClient = MongoClients.create("mongodb://192.168.31.81:27017");

        // 選擇資料庫
        MongoDatabase mongoDatabase = mongoClient.getDatabase("testdb");

        // 選擇表
        MongoCollection<Document> userCollection = mongoDatabase.getCollection("user");

        // 查詢資料 lambda
        userCollection.find().limit(10).forEach((Consumer<? super Document>) document -> {
            System.out.println(document.toJson());
        });
        // 查詢資料
//        userCollection.find().limit(10).forEach(new Consumer<Document>() {
//            @Override
//            public void accept(Document document) {
//                System.out.println(document.toJson());
//            }
//        });

        // 關閉連線
        mongoClient.close();
    }
}

2.3、CURD操作

public class TestCRUD {
    private MongoCollection<Document> mongoCollection;

    @Before
    public void init() {
        // 建立連線
        MongoClient mongoClient = MongoClients.create("mongodb://192.168.31.81:27017");

        // 選擇資料庫
        MongoDatabase mongoDatabase = mongoClient.getDatabase("testdb");

        // 選擇表
        this.mongoCollection = mongoDatabase.getCollection("user");
    }

    // 查詢age<=50並且id>=100的使用者資訊,並且按照id倒序排序,只返回id,age欄位,不返回_id欄位
    @Test
    public void testQuery() {
        this.mongoCollection.find(
                and(
                        lte("age", 50),
                        gte("id", 100)
                )
        )
                .sort(Sorts.descending("id"))
                .projection(
                        Projections.fields(
                                Projections.include("id","age"),
                                Projections.excludeId()
                        )
                )
                .forEach((Consumer<? super Document>) document -> {
                    System.out.println(document.toJson());
                });
        ;
    }

    @Test
    public void testInsert(){
        Document document = new Document("id",10001)
                .append("name", "張三")
                .append("age", 30);
        this.mongoCollection.insertOne(document);
        System.out.println("插入資料成功!");

        this.mongoCollection.find(eq("id", 10001))
                .forEach((Consumer<? super Document>) doc->{
                    System.out.println(doc.toJson());
        });
    }

    @Test
    public void testUpdate(){
        UpdateResult updateResult = this.mongoCollection
                .updateOne(eq("id", 10001), Updates.set("age", 25));
        System.out.println(updateResult);

        this.mongoCollection.find(eq("id", 10001))
                .forEach((Consumer<? super Document>) doc->{
                    System.out.println(doc.toJson());
                });
    }

    @Test
    public void testDelete(){
        DeleteResult deleteResult = this.mongoCollection.deleteOne(eq("id", 10001));
        System.out.println(deleteResult);
    }
}

2.4、面向物件操作

前面對MongoDB的操作都是基於Document物件操作,操作略顯繁瑣,下面我們通過面向物件的方式進行操作。

建立Person、Address物件:

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Person {
    private ObjectId id;
    private String name;
    private int age;
    private Address address;
}
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Address {
    private String street;
    private String city;
    private String zip;
}

編寫測試用例:

public class TestPerson {
    MongoCollection<Person> personCollection;

    @Before
    public void init() {
        //定義物件的解碼註冊器  用於對物件進行編碼解碼
        CodecRegistry pojoCodecRegistry = CodecRegistries.
                fromRegistries(MongoClientSettings.getDefaultCodecRegistry(),
                        CodecRegistries.fromProviders(PojoCodecProvider.builder().automatic(true).build()));

        // 建立連線
        MongoClient mongoClient =
                MongoClients.create("mongodb://192.168.31.81:27017");

        // 選擇資料庫 並且 註冊解碼器
        MongoDatabase mongoDatabase = mongoClient.getDatabase("testdb")
                .withCodecRegistry(pojoCodecRegistry);

        // 選擇表
        this.personCollection = mongoDatabase.getCollection("person", Person.class);
    }

    @Test
    public void testInsert() {
        Person person = new Person(ObjectId.get(), "張三", 20,
                new Address("人民路", "上海市", "666666"));
        this.personCollection.insertOne(person);
        System.out.println("插入資料成功");
    }

    @Test
    public void testInserts() {
        List<Person> personList = Arrays.asList(new Person(ObjectId.get(), "張三", 20, new Address("人民路", "上海市", "666666")),
                new Person(ObjectId.get(), "李四", 21, new Address("北京西路", "上海市", "666666")),
                new Person(ObjectId.get(), "王五", 22, new Address("南京東路", "上海市", "666666")),
                new Person(ObjectId.get(), "趙六", 23, new Address("陝西南路", "上海市", "666666")),
                new Person(ObjectId.get(), "孫七", 24, new Address("南京西路", "上海市", "666666")));
        this.personCollection.insertMany(personList);
        System.out.println("插入資料成功");
    }

    @Test
    public void testQuery() {
        this.personCollection.find(Filters.eq("name", "張三"))
                .forEach((Consumer<? super Person>) person -> {
                    System.out.println(person);
                });
    }

    @Test
    public void testUpdate() {
        UpdateResult updateResult = this.personCollection.updateMany(Filters.eq("name", "張三"), Updates.set("age", 22));
        System.out.println(updateResult);
    }

    @Test
    public void testDelete() {
        DeleteResult deleteResult = this.personCollection.deleteOne(Filters.eq("name", "張三"));
        System.out.println(deleteResult);
    }
}

3、SpringBoot整合MongoDB

SpringData框架:是 spring所提供的一個持久層框架,它對JPA(java persitence API)進行了相應的封 裝和實現。SpringDataMongodb就是對 Mongodb資料庫的CRUD進行了相應的封 裝,以減化Mongodb資料庫的開發。

spring-data對MongoDB做了支援,使用spring-data-mongodb可以簡化MongoDB的操作。

地址:https://spring.io/projects/spring-data-mongodb

第一步,匯入依賴:

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.1.0.RELEASE</version>
</parent>

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

第二步,編寫application.properties配置檔案

# Spring boot application
spring.application.name = lichee-mongodb

spring.data.mongodb.uri=mongodb://192.168.31.81:27017/testdb

第三步,編寫PersonDao

@Component
public class PersonDAO {
    @Autowired
    private MongoTemplate mongoTemplate;

    public Person savePerson(Person person){//orm影射
        return this.mongoTemplate.save(person);
    }

    public List<Person> queryPersonListByName(String name) {
        Query query = Query.query(Criteria.where("name").is(name));
        /**
         * 第一個引數:查詢條件
         * 第二個引數:查詢結果封 裝的資料型別
         */
        return this.mongoTemplate.find(query, Person.class);
    }

    /**
     *
     * @param page  頁碼
     * @param rows  每頁顯示的條數
     * @return
     */
    public List<Person> queryPagePersonList(Integer page, Integer rows) {
        //limit(10)  忽略的條數(page-1)*rows
        Query query = new Query().limit(rows).skip((page - 1) * rows);
        return this.mongoTemplate.find(query, Person.class);
    }

    public UpdateResult update(Person person) {
        Query query = Query.query(Criteria.where("id").is(person.getId()));
        //用於指定更新列
        Update update = Update.update("age", person.getAge());

        /**
         * 第一個引數:查詢條件
         * 第二個引數:指定的更新列
         * 第三個引數:指定的操作集合(和類ORM對應)
         */
        return this.mongoTemplate.updateFirst(query, update, Person.class);
    }

    public DeleteResult deleteById(String id) {
        Query query = Query.query(Criteria.where("id").is(id));
        return this.mongoTemplate.remove(query, Person.class);
    }
}

第四步,編寫啟動類

@SpringBootApplication
public class MongoApplication {
    public static void main(String[] args) {
        SpringApplication.run(MongoApplication.class, args);
    }
}

第五步,編寫單元測試

@RunWith(SpringRunner.class)
@SpringBootTest
public class TestPersonDao {
    @Autowired
    private PersonDao personDao;

    @Test
    public void testSave() {
        Person person = new Person(ObjectId.get(), "張三", 20,
                new Address("人民路", "上海市", "666666"));
        this.personDao.savePerson(person);
    }

    @Test
    public void testQuery() {
        List<Person> personList = this.personDao.queryPersonListByName("張三");
        for (Person person : personList) {
            System.out.println(person);
        }
    }

    @Test
    public void testQuery2() {
        List<Person> personList = this.personDao.queryPersonListByName(2, 2);
        for (Person person : personList) {
            System.out.println(person);
        }
    }

    @Test
    public void testUpdate() {
        Person person = new Person();
        person.setId(new ObjectId("5c0956ce235e192520086736"));
        person.setAge(30);
        this.personDao.update(person);
    }

    @Test
    public void testDelete() {
        this.personDao.deleteById("5c09ca05235e192d8887a389");
    }
}

4、MongoDB認證

MongoDB預設情況下是沒有認證的,也就是無需使用者名稱密碼登入即可訪問資料。這樣在生產環境是非常不安全的,MongoDB也提供了認證功能的,下面我們一起學習下。

#重新建立mongo容器,需要新增--auth引數
docker create --name mongodb2 -p 27018:27017 -v mongodb2:/data/db mongo:4.0.3 --auth

#啟動容器
docker start mongodb2

#進入容器進行設定
docker exec -it mongodb2 /bin/bash

#進入admin資料庫
mongo
#在admin資料庫下建立的使用者,可以管理所有的其它資料庫
use admin

#新增管理員,其擁有管理使用者和角色的許可權
db.createUser({ user: 'root', pwd: 'root', roles: [ { role: "root", db: "admin" } ] })

#測試,發現是沒有許可權操作的
> show dbs
2020-10-20T09:09:15.543+0000 E QUERY    [js] Error: listDatabases failed:{
        "ok" : 0,
        "errmsg" : "command listDatabases requires authentication",
        "code" : 13,
        "codeName" : "Unauthorized"
} :

#進行認證  退出當前登陸後重新登陸
mongo -u "root" -p "root" --authenticationDatabase "admin"

#或者通過db.auth()進行認證
use admin
db.auth("root","root");

#通過admin新增普通使用者
db.createUser({ user: 'tanhua', pwd: 'tanhua123', roles: [ { role: "readWrite", db: "tanhua" } ] });

#通過tanhua使用者登入進行測試
mongo -u "tanhua" -p "tanhua123" --authenticationDatabase "admin"
use admin

#測試
root@5d848955ff7e:/# mongo -u "tanhua" -p "tanhua123" --authenticationDatabase "admin"
MongoDB shell version v4.0.3
connecting to: mongodb://127.0.0.1:27017
Implicit session: session { "id" : UUID("6c368269-30f0-4b29-a224-05a38b5847e2") }
MongoDB server version: 4.0.3
> use tanhua
switched to db tanhua
> db.user.insert({id:1,username:'zhangsan',age:20})
WriteResult({ "nInserted" : 1 })
> db.user.find()
{ "_id" : ObjectId("5f8eb2726e0de0aa9517afd3"), "id" : 1, "username" : "zhangsan", "age" : 20 }

#檢視使用者
db.system.users.find()

db.getUsers();

show users;
# 刪除使用者
> use admin

> db.dropUser("tanhua")

或

> use admin

> db.runCommand({ dropUser: "tanhua" })
#更改使用者密碼
更改使用者tanhua密碼為tanhua。

> use admin

> db.changeUserPassword("tanhua", "dbabdnew")

可以使用提供的測試工程測試一下:

#spring.data.mongodb.uri=mongodb://192.168.31.81:27018/testdb
spring.data.mongodb.username=root
spring.data.mongodb.password=root
spring.data.mongodb.authentication-database=admin
spring.data.mongodb.database=testdb
spring.data.mongodb.port=27018
spring.data.mongodb.host=1192.168.31.81