Java操作MongoDB详解
- 1. MongoDB概述
-
- 1.1 MongoDB简介
- 1.2 MongoDB概念
- 2. MongoDB安装
-
- 2.1 MongoDB下载
- 2.2 MongoDB安装
- 2.3 MongoDB启动服务
- 3. MongoDB操作
-
- 3.1 MongoDB数据增删
- 3.2 MongoDB高级查询
- 4. MongoDB客户端工具
-
- 4.1 Studio 3T
- 4.2 Robo 3T (Robomong) 推荐
- 4.3 Navicat for MongoDB
- 4.4 NoSQLBooster for MongoDB
- 4.5 MongoDB Compass
- 5. MongoDB Java操作
- 6. MongoDB集成SpringBoot
-
- 6.1 官方文档
- 6.2 引入依赖
- 6.3 配置参数
- 6.4 代码实现
1. MongoDB概述
1.1 MongoDB简介
什么是MongoDB ? MongoDB 是由C++语言编写的,是一个基于分布式文件存储的开源数据库系统。
mongodb官网地址:https://www.mongodb.org.cn/
1.2 MongoDB概念
不管我们学习什么数据库都应该学习其中的基础概念,在mongodb中基本的概念是文档、集合、数据库,下面我们挨个介绍。
MongoDB概念解析:https://www.mongodb.org.cn/tutorial/6.html
下表将帮助您更容易理解Mongo中的一些概念:
SQL术语/概念 | MongoDB术语/概念 | 解释/说明 |
---|---|---|
database | database | 数据库 |
table | collection | 数据库表/集合 |
row | document | 数据记录行/文档 |
column | field | 数据字段/域 |
index | index | 索引 |
table joins | 表连接,MongoDB不支持 | |
primary key | primary key | 主键,MongoDB自动将_id字段设置为主键 |
数据库
一个mongodb中可以建立多个数据库。MongoDB的默认数据库为"db",该数据库存储在data目录中。MongoDB的单个实例可以容纳多个独立的数据库,每一个都有自己的集合和权限,不同的数据库也放置在不同的文件中。
文档
文档是一个键值(key-value)对(即BSON)。MongoDB 的文档不需要设置相同的字段,并且相同的字段不需要相同的数据类型,这与关系型数据库有很大的区别,也是 MongoDB 非常突出的特点。
集合
集合就是 MongoDB 文档组,类似于 RDBMS (关系数据库管理系统:Relational Database Management System)中的表格。
集合存在于数据库中,集合没有固定的结构,这意味着你在对集合可以插入不同格式和类型的数据,但通常情况下我们插入集合的数据都会有一定的关联性。
元数据
数据库的信息是存储在集合中。它们使用了系统的命名空间。
MongoDB 数据类型
2. MongoDB安装
2.1 MongoDB下载
MongoDB下载:https://www.mongodb.com/try/download
1.打开官网地址
2.选择版本与下载格式
2.2 MongoDB安装
window平台安装 MongoDB:https://www.mongodb.org.cn/tutorial/55.html
Linux平台安装MongoDB:https://www.mongodb.org.cn/tutorial/56.html
2.3 MongoDB启动服务
启动Mongodb服务:https://www.mongodb.org.cn/tutorial/59.html
window平台在你的安装目录/bin下,有一个叫mongod.exe的应用程序,这个程序就是用来启动你的mongodb服务器的。
F:\>mongodb/bin
F:\mongodb\bin>mongod --path=/data/db
3. MongoDB操作
3.1 MongoDB数据增删
MongoDB数据增删:https://www.mongodb.org.cn/tutorial/8.html
3.2 MongoDB高级查询
MongoDB高级查询:https://www.mongodb.org.cn/tutorial/34.html
4. MongoDB客户端工具
4.1 Studio 3T
Studio 3T官网下载地址:https://studio3t.com/download/
超过 100,000 的开发人员和数据库管理员使用 Studio 3T 作为 MongoDB GUI 的首选。Studio 3T 属于收费工具,30 天的免费试用期,Studio 3T 具有更多更强大的功能并提供企业支持服务,支持副本集、独立主机和分片集群连接,支持导入导出,SQL 查询,语法填充,支持 MongoDB 4.0+ 等等。适用于 Windows,macOS 和 Linux。
4.2 Robo 3T (Robomong) 推荐
官网下载地址:https://robomongo.org/download
Robo 3T 前身是 Robomongo,后被 3T 公司收购,是一款免费开源的 GUI 管理工具。支持 MongoDB 4.0+,轻量级 GUI,支持语法填充等等。适用于 Windows,macOS 和 Linux 系统。
4.3 Navicat for MongoDB
官网下载地址:http://www.navicat.com.cn/download/navicat-for-mongodb
老牌的数据库管理工具,支持多种数据库的集成,已集成 MongoDB 类型,属于付费型管理工具。好处是用会了一个 DB 版的 Navicat,所有 DB 版都会很顺手,维持一套操作习惯,如果再肌肉记忆一些快捷键,会更加高效。
4.4 NoSQLBooster for MongoDB
官网下载地址:https://nosqlbooster.com/downloads
NoSQLBooster for MongoDB(以前叫 MongoBooster)风格有点类似于 EasyUI,支持副本集,独立主机和分片群集连接,提供了全面的服务器监控工具、fluent 查询构建器、SQL 查询、查询代码、任务调度、ESNext 支持和真正的智能感知体验等。提供了付费和免费两种版本。适用于 Windows,macOS 和 Linux 系统。
4.5 MongoDB Compass
官网下载地址:https://www.mongodb.com/try/download/compass
官网教程:https://docs.mongodb.com/manual/reference/connection-string/
MongoDB 亲儿子系列,官方自己推出的 GUI 可视化管理工具,功能有限。免费简洁,不支持 SQL 查询,支持性能监控。适用于 Windows,macOS 和 Linux 系统。
5. MongoDB Java操作
MongoDB Java操作:https://www.mongodb.org.cn/drivers/4.html
1.引入依赖
https://search.maven.org/artifact/org.mongodb/mongo-java-driver/3.12.10/jar
<dependency>
<groupId>org.mongodb</groupId>
<artifactId>mongo-java-driver</artifactId>
<version>3.12.10</version>
</dependency>
2.代码实现
MongoUtils 实现MongoDB连接,创建,删除数据库,创建,删除,更新文档以及检索所有文档。
package com.jerry.market.utils;
import com.mongodb.MongoClient;
import com.mongodb.MongoCredential;
import com.mongodb.ServerAddress;
import com.mongodb.client.FindIterable;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoCursor;
import com.mongodb.client.MongoDatabase;
import com.mongodb.client.model.Filters;
import org.bson.Document;
import org.junit.Test;
import java.util.ArrayList;
import java.util.List;
/**
* MongoUtils
*
* @author zrj
* @since 2022/3/29
**/
public class MongoUtils {
/**
* 获取连接,无需密码
*/
@Test
public void getMongoConnectionByAddress() {
try {
// 连接到 mongodb 服务
MongoClient mongoClient = new MongoClient("localhost", 27017);
// 连接到数据库
MongoDatabase mongoDatabase = mongoClient.getDatabase("mongo");
System.out.println("Connect to database successfully");
MongoCollection<Document> col = mongoDatabase.getCollection("col");
FindIterable<Document> documents = col.find();
System.out.println("col documents : " + documents);
} catch (Exception e) {
System.err.println(e.getClass().getName() + ": " + e.getMessage());
}
}
/**
* 获取连接,需密码
*/
@Test
public void getMongoConnectionByUser() {
try {
//连接到MongoDB服务 如果是远程连接可以替换“localhost”为服务器所在IP地址
// ServerAddress()两个参数分别为 服务器地址 和 端口
ServerAddress serverAddress = new ServerAddress("localhost", 27017);
List<ServerAddress> addrs = new ArrayList<>();
addrs.add(serverAddress);
//MongoCredential.createScramSha1Credential()三个参数分别为 用户名 数据库名称 密码
MongoCredential credential = MongoCredential.createScramSha1Credential("username", "databaseName", "password".toCharArray());
List<MongoCredential> credentials = new ArrayList<>();
credentials.add(credential);
//通过连接认证获取MongoDB连接
MongoClient mongoClient = new MongoClient(addrs, credentials);
//连接到数据库
MongoDatabase mongoDatabase = mongoClient.getDatabase("databaseName");
System.out.println("Connect to database successfully,mongoDatabase:" + mongoDatabase);
} catch (Exception e) {
System.err.println(e.getClass().getName() + ": " + e.getMessage());
}
}
/**
* 创建集合
*/
@Test
public void createCollection() {
try {
// 连接到 mongodb 服务
MongoClient mongoClient = new MongoClient("localhost", 27017);
// 连接到数据库
MongoDatabase mongoDatabase = mongoClient.getDatabase("mongo");
System.out.println("Connect to database successfully");
mongoDatabase.createCollection("test");
System.out.println("test集合创建成功");
} catch (Exception e) {
System.err.println(e.getClass().getName() + ": " + e.getMessage());
}
}
/**
* 获取集合
*/
@Test
public void getCollection() {
try {
// 连接到 mongodb 服务
MongoClient mongoClient = new MongoClient("localhost", 27017);
// 连接到数据库
MongoDatabase mongoDatabase = mongoClient.getDatabase("mongo");
System.out.println("Connect to database successfully");
MongoCollection<Document> collection = mongoDatabase.getCollection("test");
System.out.println("集合 test 选择成功,collection:" + collection);
} catch (Exception e) {
System.err.println(e.getClass().getName() + ": " + e.getMessage());
}
}
/**
* 插入文档
*/
@Test
public void insertMany() {
try {
// 连接到 mongodb 服务
MongoClient mongoClient = new MongoClient("localhost", 27017);
// 连接到数据库
MongoDatabase mongoDatabase = mongoClient.getDatabase("mongo");
System.out.println("Connect to database successfully");
MongoCollection<Document> collection = mongoDatabase.getCollection("test");
System.out.println("集合 test 选择成功");
//插入文档
//1. 创建文档 org.bson.Document 参数为key-value的格式
//2. 创建文档集合List<Document>
//3. 将文档集合插入数据库集合中 mongoCollection.insertMany(List<Document>) 插入单个文档可以用 mongoCollection.insertOne(Document)
Document document = new Document("title", "MongoDB").append("description", "database").append("likes", 100).append("by", "Fly");
List<Document> documents = new ArrayList<>();
documents.add(document);
collection.insertMany(documents);
System.out.println("文档插入成功");
} catch (Exception e) {
System.err.println(e.getClass().getName() + ": " + e.getMessage());
}
}
/**
* 检索所有文档
*/
@Test
public void find() {
try {
// 连接到 mongodb 服务
MongoClient mongoClient = new MongoClient("localhost", 27017);
// 连接到数据库
MongoDatabase mongoDatabase = mongoClient.getDatabase("mongo");
System.out.println("Connect to database successfully");
MongoCollection<Document> collection = mongoDatabase.getCollection("test");
System.out.println("集合 test 选择成功");
//检索所有文档
//1.获取迭代器FindIterable<Document>
//2.获取游标MongoCursor<Document>
//3.通过游标遍历检索出的文档集合
FindIterable<Document> findIterable = collection.find();
MongoCursor<Document> mongoCursor = findIterable.iterator();
System.out.println("获取游标成功,mongoCursor:" + mongoCursor);
while (mongoCursor.hasNext()) {
System.out.println(mongoCursor.next());
}
System.out.println("检索所有文档完成");
} catch (Exception e) {
System.err.println(e.getClass().getName() + ": " + e.getMessage());
}
}
/**
* 更新文档
*/
@Test
public void updateMany() {
try {
// 连接到 mongodb 服务
MongoClient mongoClient = new MongoClient("localhost", 27017);
// 连接到数据库
MongoDatabase mongoDatabase = mongoClient.getDatabase("mongo");
System.out.println("Connect to database successfully");
MongoCollection<Document> collection = mongoDatabase.getCollection("test");
System.out.println("集合 test 选择成功");
//更新文档 将文档中likes=100的文档修改为likes=200
collection.updateMany(Filters.eq("likes", 100), new Document("$set", new Document("likes", 200)));
//检索查看结果
FindIterable<Document> findIterable = collection.find();
MongoCursor<Document> mongoCursor = findIterable.iterator();
System.out.println("获取游标成功,mongoCursor:" + mongoCursor);
while (mongoCursor.hasNext()) {
System.out.println(mongoCursor.next());
}
System.out.println("更新文档完成");
} catch (Exception e) {
System.err.println(e.getClass().getName() + ": " + e.getMessage());
}
}
/**
* 删除文档
*/
@Test
public void findOneRemove() {
try {
// 连接到 mongodb 服务
MongoClient mongoClient = new MongoClient("localhost", 27017);
// 连接到数据库
MongoDatabase mongoDatabase = mongoClient.getDatabase("mongo");
System.out.println("Connect to database successfully");
MongoCollection<Document> collection = mongoDatabase.getCollection("test");
System.out.println("集合 test 选择成功");
//删除符合条件的第一个文档
collection.deleteOne(Filters.eq("likes", 200));
//删除所有符合条件的文档
collection.deleteMany(Filters.eq("likes", 200));
//检索查看结果
FindIterable<Document> findIterable = collection.find();
MongoCursor<Document> mongoCursor = findIterable.iterator();
System.out.println("获取游标成功,mongoCursor:" + mongoCursor);
while (mongoCursor.hasNext()) {
System.out.println(mongoCursor.next());
}
System.out.println("删除文档完成");
} catch (Exception e) {
System.err.println(e.getClass().getName() + ": " + e.getMessage());
}
}
}
6. MongoDB集成SpringBoot
6.1 官方文档
Spring Data MongoDB官方文档
https://spring.io/projects/spring-data-mongodb
Spring Boot与Spring Data MongoDB版本兼容关系
https://docs.spring.io/spring-data/mongodb/docs/3.2.4/reference/html/#compatibility.matrix
注意事项
springboot与spring data mongoDB版本兼容问题,不同版本之间互不兼容。
6.2 引入依赖
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.5.4</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>
<!--mongodb Java驱动-->
<dependency>
<groupId>org.mongodb</groupId>
<artifactId>mongo-java-driver</artifactId>
<version>3.12.10</version>
</dependency>
</dependencies>
6.3 配置参数
application.properties
spring.data.mongodb.uri= mongodb://127.0.0.1:27017/mongo
log4j.category.org.springframework.data.mongodb=DEBUG
log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %5p %40.40c:%4L - %m%n
6.4 代码实现
Repository和Template的选择。SpringData为我们提供了两种方式对数据库进行操作,第一种是继承Repository接口,第二种是直接使用Template的方式对数据进行操作。
第一种方式,直接继承xxxRepository接口,其最终将会继承Repository标记接口,我们可以不必自己写实现类,轻松实现增删改查、分页、排序操作,但是对于比较复杂的查询,使用起来就比较费力。
第二种方式,直接使用xxxTemplate,这需要自己写实现类,但是这样增删改查可以自己控制,对于复杂查询,用起来得心应手。
EmployeeController
package com.jerry.market.controller;
import com.jerry.market.entity.Response;
import com.jerry.market.service.EmployeeService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
/**
* 员工控制器
*
* @author zrj
* @since 2022/3/29
**/
@Slf4j
@RestController
@RequestMapping("/employee")
@Api(tags = "EmployeeController", description = "员工控制器")
public class EmployeeController {
@Resource
private EmployeeService employeeService;
/**
* 新增接口
*/
@GetMapping("/create")
@ApiOperation("新增接口")
public Response create() {
return Response.success(employeeService.create());
}
/**
* 更新接口
*/
@GetMapping("/update")
@ApiOperation("更新接口")
public Response update() {
return Response.success(employeeService.update());
}
/**
* 删除接口
*/
@GetMapping("/delete")
@ApiOperation("删除接口")
public Response delete() {
return Response.success(employeeService.delete());
}
/**
* 查询接口
*/
@GetMapping("/select")
@ApiOperation("查询接口")
public Response select() {
return Response.success(employeeService.select());
}
}
Employee
package com.jerry.market.entity;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;
import org.springframework.data.mongodb.core.mapping.Field;
/**
* @author zrj
* @since 2022/3/29
**/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Document(collection = "employee") //通过collection参数指定当前实体类对应的文档
public class Employee {
@Id //用来标识主键
private String id;
private String name;
@Field("pwd") //给字段起别名
private String password;
//@Indexed 用于声明字段需要索引
}
EmployeeRepository
package com.jerry.market.repository;
import com.jerry.market.entity.Employee;
import org.springframework.data.mongodb.repository.MongoRepository;
/**
* 员工Dao
* 定义Dao接口继承MongoRepository<实体类型,主键类型>
*
* @author zrj
* @since 2022/3/29
**/
public interface EmployeeRepository extends MongoRepository<Employee, String> {
}
Response
package com.jerry.market.entity;
import lombok.Data;
import org.springframework.stereotype.Component;
/**
* 响应对象
*
* @author zrj
* @since 2022/3/23
**/
@Data
@Component
public class Response<T> {
/**
* 状态码
*/
private static String successCode = "200";
private static String successMsg = "执行成功";
private static String failCode = "500";
private static String failMsg = "执行失败";
/**
* 提示消息
*/
private String message;
/**
* 状态码
*/
private String code;
/**
* 具体返回的数据
*/
private T data;
public Response() {
}
private Response(String code, String msg) {
this.message = msg;
this.code = code;
}
private Response(String code, String message, T data) {
this.message = message;
this.code = code;
this.data = data;
}
/**
* 返回成功Response对象
*/
public static <T> Response<T> success(T data) {
return new Response<>(successCode, successMsg, data);
}
public static <T> Response<T> success(String successMessage, T data) {
return new Response<>(successCode, successMessage, data);
}
public static <T> Response<T> success(String code, String successMessage, T data) {
return new Response<>(code, successMessage, data);
}
/**
* 返回错误Response对象
*/
public static <T> Response<T> fail(String failMsg) {
return new Response<>(failCode, failMsg);
}
public static <T> Response<T> fail(String failCode, String failMsg) {
return new Response<>(failCode, failMsg);
}
public static <T> Response<T> fail(String failCode, String failMsg, T data) {
return new Response<>(failCode, failMsg, data);
}
}
EmployeeServiceImpl
package com.jerry.market.service.impl;
import cn.hutool.core.util.IdUtil;
import com.jerry.market.entity.Employee;
import com.jerry.market.repository.EmployeeRepository;
import com.jerry.market.service.EmployeeService;
import lombok.extern.slf4j.Slf4j;
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.data.mongodb.core.query.Update;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.List;
/**
* 员工接口实现类
* 第一种方式,直接继承xxxRepository接口,其最终将会继承Repository标记接口,我们可以不必自己写实现类,轻松实现增删改查、分页、排序操作,但是对于比较复杂的查询,使用起来就比较费力。
* 第二种方式,直接使用xxxTemplate,这需要自己写实现类,但是这样增删改查可以自己控制,对于复杂查询,用起来得心应手。
*
* @author zrj
* @since 2022/3/29
**/
@Slf4j
@Service
public class EmployeeServiceImpl implements EmployeeService {
@Resource
private EmployeeRepository employeeRepository;
@Resource
private MongoTemplate mongoTemplate;
/**
* 新增
*
* @return String
*/
@Override
public String create() {
//第一种方式,直接继承xxxRepository接口
Employee employee = Employee.builder().id("1").name("张三").password("123").build();
employeeRepository.save(employee);
log.info("第一种方式新增成功,employee:" + employee);
//第二种方式,直接使用xxxTemplate
//注意:id不能重复。MongoWriteException: E11000 duplicate key error collection: mongo.employee index: _id_ dup key: { _id: "3" }
Employee employee2 = Employee.builder().id(IdUtil.simpleUUID()).name("李四").password("123").build();
mongoTemplate.insert(employee2);
log.info("第二种方式新增成功,employee:" + employee2);
log.info("【员工接口】新增成功");
return "新增成功";
}
/**
* 更新
*
* @return String
*/
@Override
public String update() {
//第一种方式,直接继承xxxRepository接口
Employee employee = Employee.builder().id("1").name("张更新").password("666").build();
employeeRepository.save(employee);
//第二种方式,直接使用xxxTemplate
Query query = Query.query(Criteria.where("id").is("2").and("name").is("王小二"));
Update update = Update.update("name", "王更新");
mongoTemplate.updateFirst(query, update, Employee.class);
log.info("【员工接口】更新成功");
return "更新成功";
}
/**
* 删除
*
* @return String
*/
@Override
public String delete() {
//第一种方式,直接继承xxxRepository接口
employeeRepository.deleteById("1");
//第二种方式,直接使用xxxTemplate
Query query = Query.query(Criteria.where("id").is("2"));
mongoTemplate.remove(query, Employee.class);
log.info("【员工接口】删除成功");
return "删除成功";
}
/**
* 查询
*
* @return String
*/
@Override
public List<Employee> select() {
//第一种方式,直接继承xxxRepository接口
List<Employee> employeeList = employeeRepository.findAll();
System.out.println("第一种方式,employeeList:" + employeeList);
//第二种方式,直接使用xxxTemplate
List<Employee> employeeLists = this.mongoTemplate.findAll(Employee.class);
System.out.println("第二种方式,employeeList:" + employeeLists);
log.info("【员工接口】查询成功");
return employeeLists;
}
}
EmployeeService
package com.jerry.market.service;
import com.jerry.market.entity.Employee;
import java.util.List;
/**
* @author zrj
* @since 2022/3/29
**/
public interface EmployeeService {
/**
* 新增
* @return String
*/
String create();
/**
* 更新
* @return String
*/
String update();
/**
* 删除
* @return String
*/
String delete();
/**
* 查询
* @return String
*/
List<Employee> select();
}