MongoDB 完整指南
目录
MongoDB简介
什么是MongoDB
MongoDB是一个基于分布式文件存储的NoSQL数据库,由C++语言编写,旨在为WEB应用提供可扩展的高性能数据存储解决方案。
主要特点
- 文档导向: 数据以BSON(Binary JSON)格式存储
- 高性能: 支持索引、聚合、分片等特性
- 高可用性: 支持复制集和自动故障转移
- 水平扩展: 支持分片集群,可横向扩展
- 灵活模式: 无需预定义表结构,支持动态字段
适用场景
- 大数据量、高并发的Web应用
- 内容管理系统
- 实时分析系统
- 物联网数据存储
- 日志系统
核心概念
数据库结构
MongoDB实例
├── 数据库(Database)
│ ├── 集合(Collection) - 相当于关系数据库中的表
│ │ ├── 文档(Document) - 相当于关系数据库中的行
│ │ │ ├── 字段(Field) - 相当于关系数据库中的列
│ │ │ └── 值(Value)
│ │ └── 索引(Index)
│ └── 用户(User)
└── 配置(Configuration)
数据类型
- 基本类型: String, Number, Boolean, Date, ObjectId
- 复合类型: Array, Object, Null
- 特殊类型: Binary Data, Regular Expression, Timestamp
使用技巧
1. 索引优化
javascript
// 创建单字段索引
db.collection.createIndex({ "field": 1 })
// 创建复合索引
db.collection.createIndex({ "field1": 1, "field2": -1 })
// 创建文本索引
db.collection.createIndex({ "content": "text" })
// 创建地理空间索引
db.collection.createIndex({ "location": "2dsphere" })
2. 聚合管道
javascript
// 复杂聚合查询示例
db.orders.aggregate([
{ $match: { status: "completed" } },
{ $group: {
_id: "$customerId",
totalAmount: { $sum: "$amount" },
orderCount: { $sum: 1 }
}},
{ $sort: { totalAmount: -1 } },
{ $limit: 10 }
])
3. 批量操作
javascript
// 批量插入
db.collection.bulkWrite([
{ insertOne: { document: { name: "John", age: 30 } } },
{ insertOne: { document: { name: "Jane", age: 25 } } },
{ updateOne: { filter: { name: "John" }, update: { $set: { age: 31 } } } }
])
4. 数据验证
javascript
// 创建集合时定义验证规则
db.createCollection("users", {
validator: {
$jsonSchema: {
required: ["name", "email"],
properties: {
name: { type: "string", minLength: 2 },
email: { type: "string", pattern: "^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$" },
age: { type: "number", minimum: 0, maximum: 150 }
}
}
}
})
重难点解析
1. 事务处理
javascript
// MongoDB 4.0+ 支持多文档事务
const session = db.getMongo().startSession();
session.startTransaction();
try {
// 执行多个操作
db.accounts.updateOne(
{ _id: "account1" },
{ $inc: { balance: -100 } },
{ session }
);
db.accounts.updateOne(
{ _id: "account2" },
{ $inc: { balance: 100 } },
{ session }
);
session.commitTransaction();
} catch (error) {
session.abortTransaction();
throw error;
} finally {
session.endSession();
}
2. 分片策略
javascript
// 启用分片
sh.enableSharding("database")
// 对集合进行分片
sh.shardCollection("database.collection", { "shardKey": 1 })
// 分片键选择原则
// - 基数高(唯一值多)
// - 写分布均匀
// - 支持单调递增
3. 复制集配置
javascript
// 复制集配置示例
config = {
_id: "rs0",
members: [
{ _id: 0, host: "mongodb0.example.net:27017" },
{ _id: 1, host: "mongodb1.example.net:27017" },
{ _id: 2, host: "mongodb2.example.net:27017" }
]
}
rs.initiate(config)
4. 性能优化
javascript
// 使用投影减少数据传输
db.collection.find({}, { name: 1, email: 1, _id: 0 })
// 使用hint强制使用特定索引
db.collection.find({ field: "value" }).hint({ field: 1 })
// 使用explain分析查询性能
db.collection.find({ field: "value" }).explain("executionStats")
Spring Boot集成
1. 依赖配置
xml
<!-- Maven -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>
gradle
// Gradle
implementation 'org.springframework.boot:spring-boot-starter-data-mongodb'
2. 配置文件
yaml
# application.yml
spring:
data:
mongodb:
host: localhost
port: 27017
database: mydb
username: admin
password: password
authentication-database: admin
# 连接池配置
max-connection-pool-size: 100
min-connection-pool-size: 5
max-connection-idle-time: 30000
# 复制集配置
# uri: mongodb://user:pass@host1:port1,host2:port2/database?replicaSet=rs0
3. 实体类定义
java
@Document(collection = "users")
public class User {
@Id
private String id;
@Indexed(unique = true)
private String email;
private String name;
private int age;
@CreatedDate
private LocalDateTime createdAt;
@LastModifiedDate
private LocalDateTime updatedAt;
// 构造函数、getter、setter
}
4. Repository接口
java
@Repository
public interface UserRepository extends MongoRepository<User, String> {
// 自定义查询方法
List<User> findByName(String name);
List<User> findByAgeGreaterThan(int age);
@Query("{ 'age' : { $gte : ?0, $lte : ?1 } }")
List<User> findByAgeBetween(int minAge, int maxAge);
// 使用正则表达式
List<User> findByNameRegex(String regex);
// 分页查询
Page<User> findByAge(int age, Pageable pageable);
}
5. 服务层实现
java
@Service
public class UserService {
@Autowired
private UserRepository userRepository;
@Autowired
private MongoTemplate mongoTemplate;
// 基本CRUD操作
public User createUser(User user) {
return userRepository.save(user);
}
public User findById(String id) {
return userRepository.findById(id)
.orElseThrow(() -> new UserNotFoundException("User not found"));
}
// 使用MongoTemplate进行复杂查询
public List<User> findUsersByComplexCriteria(String name, int minAge, String city) {
Criteria criteria = new Criteria();
if (name != null) {
criteria = criteria.and("name").regex(name, "i");
}
if (minAge > 0) {
criteria = criteria.and("age").gte(minAge);
}
if (city != null) {
criteria = criteria.and("address.city").is(city);
}
Query query = new Query(criteria);
return mongoTemplate.find(query, User.class);
}
// 聚合查询
public List<AgeGroup> getUsersByAgeGroup() {
Aggregation aggregation = Aggregation.newAggregation(
Aggregation.group("age")
.count().as("count")
.avg("age").as("averageAge"),
Aggregation.sort(Sort.Direction.ASC, "_id")
);
return mongoTemplate.aggregate(aggregation, "users", AgeGroup.class)
.getMappedResults();
}
// 批量操作
@Transactional
public void updateUsersAge(String name, int newAge) {
Query query = new Query(Criteria.where("name").is(name));
Update update = new Update().set("age", newAge);
mongoTemplate.updateMulti(query, update, User.class);
}
}
6. 控制器层
java
@RestController
@RequestMapping("/api/users")
public class UserController {
@Autowired
private UserService userService;
@PostMapping
public ResponseEntity<User> createUser(@RequestBody User user) {
User createdUser = userService.createUser(user);
return ResponseEntity.status(HttpStatus.CREATED).body(createdUser);
}
@GetMapping("/{id}")
public ResponseEntity<User> getUserById(@PathVariable String id) {
User user = userService.findById(id);
return ResponseEntity.ok(user);
}
@GetMapping("/search")
public ResponseEntity<List<User>> searchUsers(
@RequestParam(required = false) String name,
@RequestParam(required = false) Integer minAge,
@RequestParam(required = false) String city) {
List<User> users = userService.findUsersByComplexCriteria(name, minAge, city);
return ResponseEntity.ok(users);
}
@GetMapping("/age-groups")
public ResponseEntity<List<AgeGroup>> getAgeGroups() {
List<AgeGroup> ageGroups = userService.getUsersByAgeGroup();
return ResponseEntity.ok(ageGroups);
}
}
7. 配置类
java
@Configuration
@EnableMongoRepositories(basePackages = "com.example.repository")
public class MongoConfig extends AbstractMongoClientConfiguration {
@Value("${spring.data.mongodb.database}")
private String databaseName;
@Override
protected String getDatabaseName() {
return databaseName;
}
@Bean
public MongoTemplate mongoTemplate() throws Exception {
return new MongoTemplate(mongoClient(), getDatabaseName());
}
// 自定义转换器
@Bean
public MongoCustomConversions customConversions() {
List<Converter<?, ?>> converters = new ArrayList<>();
converters.add(new LocalDateTimeToDateConverter());
converters.add(new DateToLocalDateTimeConverter());
return new MongoCustomConversions(converters);
}
}
最佳实践
1. 数据建模
- 嵌入文档: 适合一对少关系,数据不经常变化
- 引用文档: 适合一对多关系,数据经常变化
- 混合模式: 根据查询模式选择最优方案
2. 索引策略
- 为常用查询字段创建索引
- 避免过多索引(影响写入性能)
- 使用复合索引优化多字段查询
- 定期分析索引使用情况
3. 性能优化
- 使用投影减少数据传输
- 合理使用分页查询
- 避免深度嵌套查询
- 使用聚合管道替代应用层处理
4. 安全配置
- 启用身份验证
- 使用TLS/SSL加密
- 限制网络访问
- 定期备份数据
5. 监控和维护
- 监控连接数和性能指标
- 定期清理无用索引
- 监控磁盘空间使用
- 设置告警机制
总结
MongoDB作为NoSQL数据库的代表,具有灵活的数据模型、高性能和良好的扩展性。通过合理的数据建模、索引优化和Spring Boot集成,可以构建高效、可扩展的应用程序。
关键要点:
- 理解MongoDB的文档模型和查询语言
- 掌握索引和聚合管道的使用
- 合理设计数据模型和查询策略
- 正确配置Spring Boot集成
- 遵循最佳实践确保性能和安全性
通过本指南的学习,您应该能够熟练使用MongoDB并成功集成到Spring Boot项目中。