目录
一.MongoDB 是什么?
MongoDB 是在2007年由DoubleClick公司的几位核心成员开发出的一款分布式文档数据库,由C++语言编写。目的是为了解决数据大量增长的时候系统的可扩展性和敏捷性。MongoDB要比传统的关系型数据库简单很多。
在MongoDB中数据主要的组织结构就是数据库、集合和文档
,文档存储在集合当中,集合存储在数据库中。MongoDB中每一条数据记录就是一个文档,数据结构由键值(key=>value)对组成
。
文档类似于 JSON 对象,它的数据结构被叫做BSON
(Binary JSON)。
核心特点:
文档是一组键值(key-value)对。MongoDB 的文档不需要设置相同的字段,并且相同的字段不需要相同的数据类型,这与关系型数据库有很大的区别,也是 MongoDB 非常突出的特点。
需要注意的是:
- MongoDB区分类型和大小写。
- MongoDB的文档不能有重复的键。
Mongodb可以让同一集合(Collection)中的文档有不同的字段:
示例:同一 users
集合中存储不同结构的文档:
// 文档1:普通用户
{ _id: "1", name: "Alice", age: 25 }
// 文档2:带地址的用户
{ _id: "2", name: "Bob", addresses: [{ city: "Beijing" }] }
适用场景:
MongoDB不需要去明确指定一张表的具体结构,对字段的管理非常灵活,有很强的可扩展性。
支持高并发、高可用、高可扩展性,自带数据压缩功能,支持海量数据的高效存储和访问。
支持基本的CRUD、数据聚合、文本搜索和地理空间查询功能。
网站数据:Mongo非常适合实时的插入,更新与查询,并具备网站实时数据存储所需的复制及高度伸缩性。
高伸缩性的场景:Mongo非常适合由数十或数百台服务器组成的数据库。
大尺寸,低价值的数据:使用传统的关系型数据库存储一些数据时可能会比较昂贵,在此之前,很多时候程序员往往会选择传统的文件进行存储。
缓存:由于性能很高,Mongo也适合作为信息基础设施的缓存层。在系统重启之后,由Mongo搭建的持久化缓存层可以避免下层的数据源过载。
例如:弹幕、直播间互动信息、朋友圈信息、物流场景等。
不适用场景:
高度事务性系统:例如银行系统。传统的关系型数据库目前还是更适用于需要大量原子性复杂事务的应用程序。
传统的商业智能应用:针对特定问题的BI数据库会对产生高度优化的查询方式。对于此类应用,数据仓库可能是更合适的选择。
二.安装与下载:
1.官网下载:https://www.mongodb.com/try/download
2.基于docker镜像安装:
第一步 拉取镜像:
docker pull mongo:latest
第二步 容器启动:
首先需要在宿主机建立文件夹
rm -rf /opt/mongo
mkdir -p /opt/mongo/data/db
docker run -d --restart=always -p 27017:27017 --name mongo -v /opt/mongo/data/db:/data/db mongo:latest
最后连接mongo:
docker exec -it mongo mongosh
基本命令:
show dbs
db.version() #当前db版本
db.getMongo() #查看当前db的链接机器地址
db.help() #帮助
quit() #退出命令行
在Windows可以使用 mongodb compass 链接 MongoDB:
https://www.mongodb.com/try/download/compasshttps://www.mongodb.com/try/download/compass下载并安装指南针_MonogDB 中文网
https://mongodb.net.cn/compass/current/install/
三.SpringBoot集成MongoDB :
MongoDB Java | 菜鸟教程https://www.runoob.com/mongodb/mongodb-java.htmlspring-data-mongodb 提供了
MongoTemplate
与 MongoRepository
两种方式访问 mongodb,MongoRepository 操作简单,MongoTemplate 操作灵活,我们在项目中可以灵活使用这两种方式操作mongodb。
首先引入依赖:
<!--mongodb-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>
随后编写配置文件:
spring:
data:
mongodb:
database: daijia
host: 192.168.1.101
port: 27017
之后创建实体类:
ObjectId
是文档(Document)的默认主键类型(_id
字段),用于唯一标识集合中的每个文档。每个ObjectId
是一个 12 字节(24 位十六进制字符串) 的值,由以下部分组成:
字节位置
内容
说明
0-3
时间戳
精确到秒,表示文档创建时间
4-6
机器标识
生成该 ID 的机器/进程的唯一标识
7-8
进程 ID
确保同一机器上不同进程的 ID 不冲突
9-11
计数器
每秒的递增序列,确保同一秒内的 ID 唯一
示例:
5f1d5a8e6d8e4d2a3c9e3b1a
(实际存储为 BSON 格式,显示时转为十六进制字符串)
import lombok.Data;
import org.bson.types.ObjectId;
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;
import java.util.Date;
@Data
@Document("user") //指定mongodb中的集合名字
public class User {
@Id
private ObjectId id;
private String name;
private Integer age;
private String email;
private Date createDate;
}
使用 MongoRepository:
首先添加 Repository 类:
这里的泛型:<实体类类型,主键类型>
import com.atguigu.mongo_demo.model.User;
import org.bson.types.ObjectId;
import org.springframework.data.mongodb.repository.MongoRepository;
public interface UserRepository extends MongoRepository<User, ObjectId> {
}
之后创建测试类。test目录创建测试类:MongoRepositoryTest
其中的Optional对象是 Java 8 引入的一个容器类,主要用于优雅地处理可能为
null
的值,避免NullPointerException
(空指针异常),一般用于查询时的返回对象类型。
import com.atguigu.mongo_demo.model.User;
import com.atguigu.mongo_demo.repository.UserRepository;
import org.bson.types.ObjectId;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.domain.Example;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import java.util.Date;
import java.util.List;
import java.util.Optional;
@SpringBootTest
public class MongoRepositoryTest {
@Autowired // 自动注入UserRepository实例
private UserRepository userRepository;
/**
* 测试插入用户数据
* 1. 创建User对象并设置属性
* 2. 调用save()方法保存到MongoDB
*/
@Test
public void testCreateUser(){
User user = new User();
user.setName("小谷"); // 设置用户名
user.setAge(19); // 设置年龄
user.setCreateDate(new Date()); // 设置创建时间为当前时间
userRepository.save(user); // 保存到数据库
}
/**
* 测试查询所有用户
* 使用findAll()方法获取所有用户列表
*/
@Test
public void testFindAll(){
List<User> userList = userRepository.findAll(); // 查询所有用户
System.out.println(userList); // 打印结果
}
/**
* 测试根据ID查询用户
* 1. 使用ObjectId构造查询条件
* 2. 使用findById()方法查询
* 3. 使用Optional处理可能为空的结果
*/
@Test
public void testFindById(){
// 根据ID查询用户,返回Optional对象
Optional<User> optional = userRepository.findById(
new ObjectId("64eee9dff317c823c62b4faf") // 使用字符串构造ObjectId
);
boolean present = optional.isPresent(); // 判断是否存在
if(present){
User user = optional.get(); // 获取用户对象
System.out.println(user); // 打印用户信息
}
}
/**
* 测试条件查询
* 1. 创建示例对象
* 2. 使用findAll(Example)方法查询
*/
@Test
public void testFindAllExample(){
User user = new User();
user.setAge(19); // 设置查询条件:年龄=19
Example<User> example = Example.of(user); // 创建查询示例
List<User> userList = userRepository.findAll(example); // 执行查询
System.out.println(userList); // 打印结果
}
/**
* 测试排序查询
* 1. 创建Sort对象指定排序规则
* 2. 使用findAll(Sort)方法查询
*/
@Test
public void testFindAllSort(){
// 创建排序规则:按age字段降序
Sort sort = Sort.by(Sort.Direction.DESC, "age");
List<User> userList = userRepository.findAll(sort); // 执行排序查询
System.out.println(userList); // 打印结果
}
/**
* 测试分页查询
* 1. 创建PageRequest对象指定分页参数
* 2. 使用findAll(Pageable)方法查询
* 3. 从Page对象获取分页信息
*/
@Test
public void testFindAllPage(){
// 创建分页请求:第0页,每页10条
PageRequest pageRequest = PageRequest.of(0, 10);
Page<User> page = userRepository.findAll(pageRequest); // 执行分页查询
int totalPages = page.getTotalPages(); // 获取总页数
List<User> userList = page.getContent(); // 获取当前页数据
System.out.println(userList); // 打印当前页数据
System.out.println(totalPages); // 打印总页数
}
/**
* 测试更新用户
* 1. 先查询出要更新的用户
* 2. 修改用户属性
* 3. 调用save()方法更新
* 注意:save()方法会根据_id判断是插入还是更新
*/
@Test
public void testUpdateUser(){
// 先查询要更新的用户
Optional<User> optional = userRepository.findById(
new ObjectId("64eee9dff317c823c62b4faf")
);
if(optional.isPresent()){
User user = optional.get();
user.setAge(100); // 修改年龄
// 保存更新:由于user对象包含_id,会执行更新操作
userRepository.save(user);
System.out.println(user); // 打印更新后的用户
}
}
/**
* 测试删除用户
* 使用deleteById()方法根据ID删除用户
*/
@Test
public void testDeleteUser(){
userRepository.deleteById(
new ObjectId("64eee9dff317c823c62b4faf") // 根据ID删除用户
);
}
}
使用 MongoTemplate:
test目录创建测试类:MongoTemplateTest
Criteria
是 Spring Data MongoDB 提供的条件查询构建器,用于以面向对象的方式构造 MongoDB 查询条件。它通常与Query
类配合使用,实现灵活的条件组合。
import com.atguigu.mongo_demo.model.User;
import com.mongodb.client.result.DeleteResult;
import com.mongodb.client.result.UpdateResult;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
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 java.util.List;
import java.util.regex.Pattern;
@SpringBootTest
public class MongoTemplateTest {
@Autowired // 自动注入MongoTemplate实例
private MongoTemplate mongoTemplate;
/**
* 测试添加用户
* 使用mongoTemplate.insert()方法插入新文档
*/
@Test
public void testCreateUser(){
User user = new User();
user.setAge(20); // 设置年龄
user.setName("test"); // 设置姓名
user.setEmail("test@qq.com"); // 设置邮箱
mongoTemplate.insert(user); // 插入到集合(若集合不存在会自动创建)
System.out.println(user); // 打印插入后的用户对象(包含自动生成的_id)
}
/**
* 测试查询所有用户
* 使用mongoTemplate.findAll()查询集合中所有文档
*/
@Test
public void testFindUser() {
List<User> userList = mongoTemplate.findAll(User.class); // 查询User集合所有文档
System.out.println(userList); // 打印结果列表
}
/**
* 测试根据ID查询用户
* 使用mongoTemplate.findById()通过主键查询
*/
@Test
public void testFindUserById(){
// 根据ID查询用户(注意_id是String类型时直接传入字符串)
User user = mongoTemplate.findById("64eeeae31711344f35635788", User.class);
System.out.println(user); // 打印查询结果
}
/**
* 测试删除用户
* 1. 构建查询条件(根据_id删除)
* 2. 使用mongoTemplate.remove()执行删除
* 3. 通过DeleteResult获取删除结果
*/
@Test
public void testRemove() {
// 构建条件:_id等于指定值
Criteria criteria = Criteria.where("_id").is("64eeeae31711344f35635788");
Query query = new Query(criteria); // 创建查询对象
// 执行删除,返回删除结果
DeleteResult result = mongoTemplate.remove(query, User.class);
long count = result.getDeletedCount(); // 获取实际删除的文档数
System.out.println(count); // 打印删除数量(1表示成功,0表示未找到)
}
/**
* 测试条件查询(AND)
* 1. 构建组合条件(name="test" AND age=20)
* 2. 使用mongoTemplate.find()查询匹配文档
*/
@Test
public void findUserList() {
// 构建组合条件
Criteria criteria = Criteria.where("name").is("test").and("age").is(20);
Query query = new Query(criteria); // 创建查询对象
// 执行查询
List<User> userList = mongoTemplate.find(query, User.class);
System.out.println(userList); // 打印匹配结果
}
/**
* 测试分页查询
* 1. 先查询总记录数(count)
* 2. 使用skip()和limit()实现分页
*/
@Test
public void findUsersPage() {
Query query = new Query(); // 空查询条件
// 查询总记录数
long count = mongoTemplate.count(query, User.class);
System.out.println("总记录数:" + count);
// 分页查询:跳过0条,限制返回2条(第一页,每页2条)
List<User> userList = mongoTemplate.find(
query.skip(0).limit(2),
User.class
);
System.out.println(userList); // 打印当前页数据
}
/**
* 测试更新用户
* 1. 构建查询条件(根据_id)
* 2. 使用Update对象设置更新内容
* 3. 使用upsert()更新(不存在则插入)
* 4. 通过UpdateResult获取更新结果
*/
@Test
public void testUpdateUser() {
// 构建条件:_id等于指定值
Criteria criteria = Criteria.where("_id").is("64eeeae31711344f35635788");
Query query = new Query(criteria);
// 创建更新操作
Update update = new Update();
update.set("name", "zhangsan"); // 设置name字段新值
update.set("age", 99); // 设置age字段新值
// 执行更新(upsert: 存在则更新,不存在则插入)
UpdateResult result = mongoTemplate.upsert(query, update, User.class);
// 如果用updateMulti()会更新所有匹配文档
long count = result.getModifiedCount(); // 获取实际修改的文档数
System.out.println("修改数量:" + count); // 1表示成功修改
}
}