MongoDB 常见功能详解及 Spring Cloud 集成代码展示
一、MongoDB 核心功能详解
1. 文档数据模型
- BSON 格式:二进制 JSON,支持更多数据类型(Date、Binary 等)
- 动态模式:同一集合中文档结构可不同
- 嵌套文档:支持多层嵌套结构
{
_id: ObjectId("507f191e810c19729de860ea"),
name: "张三",
address: {
city: "北京",
street: "朝阳区"
},
hobbies: ["阅读", "游泳"]
}
2. 索引机制
| 索引类型 | 描述 | 创建示例 |
|---|---|---|
| 单字段索引 | 加速单个字段查询 | db.users.createIndex({age: 1}) |
| 复合索引 | 多字段联合查询优化 | db.users.createIndex({name: 1, age: -1}) |
| 多键索引 | 数组字段索引 | db.users.createIndex({hobbies: 1}) |
| 文本索引 | 全文搜索支持 | db.articles.createIndex({content: "text"}) |
| 地理空间索引 | 地理位置查询 | db.places.createIndex({loc: "2dsphere"}) |
| TTL索引 | 自动过期删除数据 | db.logs.createIndex({createdAt: 1}, {expireAfterSeconds: 3600}) |
3. 聚合框架
// 统计不同年龄段用户数量
db.users.aggregate([
{ $match: { status: "active" } },
{ $bucket: {
groupBy: "$age",
boundaries: [20, 30, 40, 50],
output: {
count: { $sum: 1 },
names: { $push: "$name" }
}
}}
])
4. 事务支持
// MongoDB 4.0+ 多文档事务
session = db.getMongo().startSession();
session.startTransaction();
try {
db.accounts.updateOne(
{ _id: "A001", balance: { $gte: 100 } },
{ $inc: { balance: -100 } }
);
db.accounts.updateOne(
{ _id: "B002" },
{ $inc: { balance: 100 } }
);
session.commitTransaction();
} catch (error) {
session.abortTransaction();
throw error;
}
5. 变更流(Change Streams)
// 监听集合变更
const changeStream = db.orders.watch();
changeStream.on("change", (change) => {
print("Change detected: ", change);
});
6. 分片集群
- 组件:Mongos(路由)、Config Server(元数据)、Shard(数据分片)
- 分片键选择:高基数、低频率、不可变
- 分片策略:范围分片、哈希分片
二、Spring Cloud 集成 MongoDB
1. 依赖配置
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>
2. 配置连接
application.yml:
spring:
data:
mongodb:
uri: mongodb://user:password@host1:27017,host2:27017/database?replicaSet=rs0&authSource=admin
# 或者分开配置
# host: localhost
# port: 27017
# database: test
# username: user
# password: pass
# authentication-database: admin
3. 实体类映射
@Document(collection = "users")
public class User {
@Id
private String id;
@Indexed(unique = true)
private String username;
private String email;
private int age;
@Field("join_date")
private Date joinDate;
@DBRef
private List<Role> roles;
// Getters and setters
}
4. Repository 接口
public interface UserRepository extends MongoRepository<User, String> {
// 方法名自动查询
List<User> findByAgeBetween(int minAge, int maxAge);
// 分页查询
Page<User> findByEmailContaining(String domain, Pageable pageable);
// 自定义查询
@Query("{'joinDate': {$gte: ?0, $lte: ?1}}")
List<User> findUsersByJoinDateRange(Date start, Date end);
}
5. MongoTemplate 操作
@Autowired
private MongoTemplate mongoTemplate;
// 复杂查询
public List<User> findActiveUsers(String city) {
Criteria criteria = new Criteria().andOperator(
Criteria.where("age").gt(18),
Criteria.where("address.city").is(city),
Criteria.where("status").is("ACTIVE")
);
Query query = new Query(criteria)
.with(Sort.by("joinDate").descending())
.limit(100);
return mongoTemplate.find(query, User.class);
}
// 更新操作
public void updateEmail(String userId, String newEmail) {
Query query = new Query(Criteria.where("id").is(userId));
Update update = new Update().set("email", newEmail);
mongoTemplate.updateFirst(query, update, User.class);
}
6. 聚合操作
// 统计不同城市的用户数
public Map<String, Long> countUsersByCity() {
TypedAggregation<User> aggregation = Aggregation.newAggregation(
User.class,
Aggregation.group("address.city").count().as("count"),
Aggregation.project("count").and("_id").as("city")
);
AggregationResults<CityCount> results =
mongoTemplate.aggregate(aggregation, CityCount.class);
return results.getMappedResults().stream()
.collect(Collectors.toMap(CityCount::getCity, CityCount::getCount));
}
// 结果接收类
@Getter @Setter
public static class CityCount {
private String city;
private long count;
}
7. 事务管理
@Autowired
private MongoTransactionManager transactionManager;
@Transactional
public void transferPoints(String from, String to, int points) {
// 减少发送方积分
Query query1 = new Query(Criteria.where("username").is(from));
Update update1 = new Update().inc("points", -points);
mongoTemplate.updateFirst(query1, update1, User.class);
// 增加接收方积分
Query query2 = new Query(Criteria.where("username").is(to));
Update update2 = new Update().inc("points", points);
mongoTemplate.updateFirst(query2, update2, User.class);
}
8. 变更流监听
@Bean
public ChangeStreams changeStreams(MongoTemplate mongoTemplate) {
return new ChangeStreams(mongoTemplate);
}
@Component
public class ChangeStreams {
private final MongoTemplate mongoTemplate;
@Autowired
public ChangeStreams(MongoTemplate mongoTemplate) {
this.mongoTemplate = mongoTemplate;
listenToUserChanges();
}
private void listenToUserChanges() {
ChangeStreamOptions options = ChangeStreamOptions.builder()
.filter(Aggregation.newAggregation(match(where("operationType").in("insert", "update")))
.build();
mongoTemplate.changeStream("users", options, User.class)
.forEach(event -> {
System.out.println("Change detected: " + event.getBody());
// 处理变更事件
});
}
}
三、性能优化策略
-
索引优化
- 使用
explain()分析查询性能 - 创建复合索引覆盖常用查询
@Document @CompoundIndexes({ @CompoundIndex(name = "name_age_idx", def = "{'name': 1, 'age': -1}") }) public class User { ... } - 使用
-
读写分离
@ReadPreference(ReadPreferenceMode.SECONDARY) public interface UserRepository extends MongoRepository<User, String> { ... } -
批量操作
// 批量插入 List<User> users = ...; mongoTemplate.insert(users, User.class); // 批量更新 BulkOperations bulkOps = mongoTemplate.bulkOps(BulkOperations.BulkMode.UNORDERED, User.class); users.forEach(user -> { Query query = new Query(Criteria.where("id").is(user.getId())); Update update = new Update().set("status", user.getStatus()); bulkOps.updateOne(query, update); }); bulkOps.execute(); -
连接池配置
spring: data: mongodb: uri: mongodb://host/db?maxPoolSize=50&minPoolSize=5&maxIdleTimeMS=30000
四、安全与运维实践
-
安全配置
spring: data: mongodb: uri: mongodb://user:password@host/db?authSource=admin&ssl=true -
数据加密
- 启用 TLS/SSL 传输加密
- 使用 MongoDB 企业版字段级加密
-
备份策略
# 使用 mongodump 备份 mongodump --uri="mongodb://user:pass@host/db" --out=/backup # 使用 Ops Manager 或 Cloud Manager 管理备份 -
监控指标
// Spring Boot Actuator 集成 management: endpoints: web: exposure: include: health,metrics,mongodb metrics: tags: application: ${spring.application.name}
五、常见问题解决方案
-
连接超时
spring: data: mongodb: uri: mongodb://host/db?connectTimeoutMS=3000&socketTimeoutMS=5000 -
事务重试
@Retryable(value = MongoTransactionException.class, maxAttempts = 3) @Transactional public void performTransaction() { ... } -
分片键选择
- 原则:高基数、低频率、不可变
- 避免热点:使用哈希分片键
@Sharded public class Order { @ShardKey(shardKeyType = ShardKeyType.HASHED) private String orderId; } -
内存优化
// 使用 $project 减少返回数据 db.orders.aggregate([ { $match: { status: "completed" } }, { $project: { _id: 1, total: 1 } } ])
生产建议:
- 使用副本集确保高可用
- 启用访问控制(RBAC)
- 定期执行
compact回收磁盘空间- 使用 Profiler 分析慢查询
- 设置合理的 WiredTiger 缓存大小(建议50-80%内存)
以上内容涵盖了 MongoDB 的核心功能和 Spring Cloud 集成方案,包括文档模型、索引策略、聚合操作、事务管理以及性能优化等关键实践。
167万+

被折叠的 条评论
为什么被折叠?



