MongoDB
MongoDB
MongoDB简介
MongoDB是一种开源的文档型数据库管理系统,属于NoSQL数据库的一种。它使用类似JSON的BSON(Binary JSON)格式来存储数据,这使得数据在应用程序中更容易映射,同时支持动态模式,使得在开发过程中可以更灵活地调整数据模型。
MongoDB 支持动态模式的特性
- 无需预定义表结构: 你无需在数据库中预先定义表结构,可以直接插入包含不同字段的文档。
- 字段的数据类型可以随时变化: MongoDB 的文档可以包含不同数据类型的字段,而且这些字段的数据类型可以随时变化。
- 灵活的嵌套文档: MongoDB 支持在文档中嵌套其他文档,这使得可以轻松表示复杂的数据结构,而无需提前定义关联。
- 可选的字段: 你可以选择性地在文档中包含字段,而不需要每个文档都有相同的字段。
- 动态添加字段: 你可以在插入文档时动态地添加新字段,而无需修改模式。
- 索引的灵活性: MongoDB 允许你根据查询需求动态创建索引,以提高查询性能。
重要概念和特性
- 集合(Collection): MongoDB的数据存储在集合中,集合类似于关系数据库中的表。每个集合包含多个文档,每个文档都是一个键值对的BSON对象。
- 文档(Document): MongoDB中的基本数据单元是文档。文档是一组键值对,其中值可以是各种类型的数据,包括嵌套文档和数组。
- 索引(Index): MongoDB支持创建索引来提高查询性能。通过在字段上创建索引,可以加速对这些字段的查询操作。MongoDB支持单字段索引、复合索引和全文索引等。
- 聚合框架(Aggregation Framework): MongoDB提供了强大的聚合框架,允许对文档进行多个阶段的数据处理和转换。这对于数据聚合、统计和数据分析非常有用。
- 事务(Transactions): 从MongoDB 4.0版本开始,MongoDB引入了支持多文档事务的功能。这使得在一个事务中可以执行多个操作,保证数据的一致性和可靠性。
- 安全性: MongoDB提供了访问控制、身份验证和加密等安全特性,以确保数据库的安全性。管理员可以设置用户权限和角色,限制用户对数据库的访问。
- GridFS: 用于存储和检索大文件的规范,它允许将大文件分割成小块并存储在MongoDB中,支持高效的文件检索。
- MongoDB Atlas: MongoDB提供了云托管服务MongoDB Atlas,它简化了MongoDB的部署、管理和扩展。通过MongoDB Atlas,用户可以在云中轻松创建和管理MongoDB数据库实例。
- 驱动支持: MongoDB有各种语言的官方驱动程序,包括但不限于Java、Python、Node.js、C#等,使得开发者能够使用他们喜欢的编程语言与数据库进行交互。
分库分表方案劣势
分库分表就是想用数据库支持大数据量搞出来的方案,数据库本身的结构其实不擅长处理大量数据。
分库分表作为数据库优化的一种非常经典的优化方案,特别是在以前NoSQL还不是很成熟的年代,
这个方案就如救命草一般的存在。分库分表是一种优化成本很大的方案,后期会花费大量时间和精力
去处理数据,迁移数据。因此分库分表是实在没有办法的办法,应放到最后选择。优先选择NoSQL
代替,NoSQL诞生基本上为了扩展性与高性能。
适用场景
支持大量字段。实际使用时要避免join,直接建宽表。不适合关联查询。MongoDB 是一种灵活、高性能的文档型数据库,适用于多种不同的场景。以下是一些 MongoDB 的适用场景:
- 大规模数据存储: MongoDB 可以轻松处理大规模的数据存储需求,支持横向扩展,适合应对海量数据。
- 实时分析和报告: MongoDB 的灵活的数据模型和丰富的查询功能使其成为实时分析和报告的理想选择。你可以存储和查询大量的结构化和半结构化数据。
- 内容管理系统: MongoDB 适用于内容管理系统,其中经常需要存储和检索各种类型的数据,例如文章、图片、视频等。
- 日志和事件记录: MongoDB 的写入性能很高,因此适合用于处理大量的日志和事件记录。它可以支持高吞吐量的写操作。
- 用户数据管理: MongoDB 可以存储用户数据,适用于用户管理、身份验证和权限控制。它还能处理不断变化的用户属性。
- 物联网(IoT)应用: MongoDB 在物联网应用中的动态模型和横向扩展的能力使其能够存储和查询与设备、传感器和事件相关的数据。
- 位置数据存储: MongoDB 支持地理空间查询,因此适用于存储和查询与地理位置相关的数据,如地图应用或位置感知系统。
- 缓存层: MongoDB 可以用作缓存层,用于存储和检索经常访问的数据,提高应用程序的读取性能。
- 实时数据分析: MongoDB 在实时数据分析场景中表现良好,支持复杂的聚合操作和实时数据处理。
- 开发和原型设计: MongoDB 的灵活模式和简单的API使其成为开发和原型设计的理想数据库,尤其是在快速迭代的敏捷开发环境中。
使用示例
示例以spring-boot-data-mongodb 4.2.3 为例
实体建立文档集合映射
@Document(collection = "users")
@Data
public class User {
@Id
private String id;
private String username;
private String email;
private int age;
}
数据库中集合结构如下图所示:
_id和_class是默认字段
YAML配置如下所示:
spring:
application:
name: test
data:
mongodb:
uri:mongodb://127.0.0.1:27017/test?retryWrites=false
server:
servlet:
context-path: /test
port: 8081
MAVEN的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>guru.springframework</groupId>
<artifactId>spring-boot-mongodb</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>spring-boot-mongodb</name>
<description>Demo project for Spring Boot and Mongo DB</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.2.3</version>
<relativePath/>
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>21</java.version>
</properties>
<dependencies>
<dependency>
<groupId>com.fasterxml</groupId>
<artifactId>classmate</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
</dependency>
</dependencies>
</project>
部分代码展示:
UserController.java
package guru.springframework.controllers;
import guru.springframework.api.CommonResult;
import guru.springframework.domain.User;
import guru.springframework.services.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@RequestMapping("/users")
public class UserController {
@Autowired
private UserService userService;
/**
*通过用户名查询用户
*/
@GetMapping("/findUser/{username}")
public User getUserByUsername(@PathVariable String username) {
User user = userService.findByUsername(username);
return user;
}
/**
* 获取所有用户
*/
@GetMapping("/getAllUsers")
public CommonResult getAllUsers() {
List<User> users = userService.getAllUsers();
users.forEach(user -> System.out.println(user));
return CommonResult.success(users);
}
/**
* 新增或更新用户
*/
@PostMapping("/createUser")
public CommonResult createUser(@RequestBody User user) {
return CommonResult.success(userService.saveUser(user));
}
/**
* 查询年龄大于age
*/
@GetMapping("/getUsersByAgeGreaterThan/{age}")
public CommonResult getUsersByAgeGreaterThan(@PathVariable int age) {
return CommonResult.success(userService.getUsersByAgeGreaterThan(age));
}
/**
*分页查询用户
*/
@GetMapping("/getUsersByPage")
public CommonResult getUsersByPage(@RequestParam(defaultValue = "0") int pageNumber,
@RequestParam(defaultValue = "10") int pageSize) {
return CommonResult.success(userService.getUsersByPage(pageNumber, pageSize));
}
/**
* 分页查询用户并按年龄倒序
*/
@GetMapping("/getUsersByPageAndSort")
public CommonResult getUsersByPageAndSort(@RequestParam(defaultValue = "0") int pageNumber,
@RequestParam(defaultValue = "10") int pageSize) {
return CommonResult.success(userService.getUsersByPageAndSort(pageNumber, pageSize));
}
/**
* 新增或更新用户支持事务
*/
@PostMapping("/saveUserWithTransaction")
public CommonResult saveUserWithTransaction(@RequestBody User user) {
userService.saveUserWithTransaction(user);
return CommonResult.success(null);
}
}
UserService.java
package guru.springframework.services;
import guru.springframework.domain.User;
import guru.springframework.repositories.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.mongodb.MongoTransactionManager;
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.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
@Service
public class UserService {
@Autowired
private UserRepository userRepository;
@Autowired
private MongoTemplate mongoTemplate;
@Autowired
private MongoTransactionManager transactionManager;
public User findByUsername(String username) {
return userRepository.findByUsername(username);
}
public User saveUser(User user) {
return userRepository.save(user);
}
public List<User> getAllUsers() {
return userRepository.findAll();
}
public User getUserById(String userId) {
return userRepository.findById(userId).orElse(null);
}
//查询年龄大于20的用户
public List<User> getUsersByAgeGreaterThan(int age) {
Query query = new Query(Criteria.where("age").gt(age));
List<User> users = mongoTemplate.find(query, User.class);
return users;
}
//分页查询用户
public Page<User> getUsersByPage(int pageNumber, int pageSize) {
PageRequest pageRequest = PageRequest.of(pageNumber, pageSize);
return userRepository.findAll(pageRequest);
}
//分页查询按年龄倒序
public Page<User> getUsersByPageAndSort(int pageNumber, int pageSize) {
PageRequest pageRequest = PageRequest.of(pageNumber, pageSize);
return userRepository.findAllByOrderByAgeDesc(pageRequest);
}
/**
* 保存用户添加事务支持,需要mongodb 4.0以上
*/
@Transactional
public void saveUserWithTransaction(User user) {
try {
userRepository.save(user);
int x = 1 / 0;
} catch (Exception e) {
e.printStackTrace();
transactionManager.rollback(transactionManager.getTransaction(null));
}
}
}
UserRepository.java
package guru.springframework.repositories;
import guru.springframework.domain.User;
import org.springframework.data.mongodb.repository.MongoRepository;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Repository;
@Repository
public interface UserRepository extends MongoRepository<User, String> {
User findByUsername(String username);
// 分页查询所有用户
Page<User> findAll(Pageable pageable);
// 按照age字段倒序排序的分页查询
Page<User> findAllByOrderByAgeDesc(Pageable pageable);
}
项目源码及调试
Github下载地址:https://github.com/caohuajin/mongodb/
ApiPost在线接口:https://console-docs.apipost.cn/preview/1265c924445d8b22/2cdc6b3971763508