在互联网项目开发中,面对海量非结构化或半结构化数据(如用户行为日志、商品评论、地理位置信息),传统关系型数据库的固定表结构往往显得捉襟见肘。而 MongoDB 作为主流的文档型 NoSQL 数据库,凭借其 Schema 灵活、高可扩展、原生支持分布式的特性,已成为处理这类数据的首选方案。本文将从实战角度出发,为你完整演示 MongoDB 的安装配置、Spring Boot 集成、核心 CRUD 操作,以及高频实用的聚合查询与地理空间查询,帮你快速落地文档数据库解决方案!本文中涉及的技术资源与讨论,也可以在 云栈社区 找到更多。
一、实战场景与技术选型
1. 业务场景说明
本次实战围绕“电商平台用户行为分析与商品评论管理”展开,核心数据特点如下:
- 用户行为日志:非结构化,字段灵活(例如浏览、点击、下单等不同行为的字段差异很大)。
- 商品评论:半结构化,包含用户信息、评论内容、评分、时间、地理位置等多维度数据。
- 核心需求:需要支持灵活的数据插入、复杂条件查询、评论统计分析(例如按评分分组统计),以及附近用户评论查询(地理空间检索)。
2. 技术选型
- 文档数据库:MongoDB 6.x(稳定版,支持聚合管道、地理空间索引等核心特性)。
- 开发框架:Spring Boot 2.7.x(简化项目配置和开发)。
- 数据访问层:Spring Data MongoDB(它极大地简化了 MongoDB 操作,并提供了强大的 Repository 接口)。
- 其他工具:Lombok(简化代码)、FastJSON(JSON 处理)。
二、前置准备:MongoDB安装与核心配置
1. MongoDB安装(Windows/Linux通用)
(1)下载与安装
- 官网下载:访问 MongoDB 官网,选择对应操作系统的 6.x 社区版。
- Windows安装:双击安装包,选择“Complete”完整安装,可以勾选“Install MongoDB Compass”(官方可视化工具,可选)。
- Linux安装:以 CentOS 为例,可以通过 yum 安装。
- 配置 MongoDB yum 源。
- 执行
yum install -y mongodb-org。
- 启动服务:
systemctl start mongod;设置开机自启:systemctl enable mongod。
(2)验证安装
- 命令行验证:执行
mongo 或 mongosh(MongoDB 6.x 推荐),进入 MongoDB 交互终端,若显示 mongodb> 则安装成功。
- 基础命令测试:
- 查看数据库列表:
show dbs。
- 创建/切换数据库:
use ecommerce_db(切换到 ecommerce_db 数据库,不存在则自动创建)。
- 创建集合:
db.createCollection(“user_behavior”)(创建用户行为日志集合)。
2. MongoDB核心配置(优化性能与安全)
MongoDB 默认配置文件路径:
- Windows:
C:\Program Files\MongoDB\Server\6.0\bin\mongod.cfg
- Linux:
/etc/mongod.conf
(1)核心配置优化
# 存储配置
storage:
dbPath: /var/lib/mongo # 数据存储目录(Linux),Windows默认C:\data\db
journal:
enabled: true # 开启日志持久化,防止数据丢失
wiredTiger: # 存储引擎(默认WiredTiger,高性能支持并发)
engineConfig:
cacheSizeGB: 2 # 缓存大小(建议设为物理内存的50%)
# 网络配置
net:
port: 27017 # 默认端口
bindIp: 0.0.0.0 # 允许所有IP访问(生产环境建议指定具体IP)
# 安全配置(生产环境必开)
security:
authorization: enabled # 开启身份认证
# 日志配置
systemLog:
destination: file
path: /var/log/mongodb/mongod.log # 日志路径
logAppend: true # 日志追加模式
(2)创建管理员用户与数据库用户
开启身份认证后,必须创建用户才能访问,步骤如下:
- 暂时关闭身份认证,启动 MongoDB。
- 进入交互终端,创建管理员用户:
use admin
db.createUser({
user: “admin”,
pwd: “admin123”,
roles: [{ role: “root”, db: “admin” }] // 超级管理员权限
})
- 开启身份认证,重启 MongoDB。
- 使用管理员账号登录,创建业务数据库用户(例如 ecommerce_db):
mongosh -u admin -p admin123 --authenticationDatabase admin
use ecommerce_db
db.createUser({
user: “ecommerce_user”,
pwd: “ecommerce123”,
roles: [{ role: “readWrite”, db: “ecommerce_db” }] // 读写权限
})
3. MongoDB可视化工具使用(MongoDB Compass)
MongoDB Compass 是官方提供的可视化工具,便于数据查看和操作:
- 连接数据库:输入主机、端口、认证数据库、用户名和密码,点击“Connect”。
- 核心功能:可以直观地查看集合数据、执行查询语句、创建索引、导出数据等,非常适合开发和调试阶段使用。
三、Spring Boot集成Spring Data MongoDB
Spring Data MongoDB 提供了一套高度简化的 API,支持 Repository 接口、注解式查询等功能,能大幅降低 MongoDB 操作的成本。
1. 核心依赖引入
在 pom.xml 中添加 Spring Boot Web、Spring Data MongoDB、Lombok 等依赖:
<dependencies>
<!-- Spring Boot Web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Spring Data MongoDB -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>
<!-- Lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
2. 基础配置(application.yml)
配置 MongoDB 连接信息、连接池优化等参数:
spring:
data:
mongodb:
uri: mongodb://ecommerce_user:ecommerce123@127.0.0.1:27017/ecommerce_db?authSource=ecommerce_db
# 可选:分参数配置(与uri二选一)
# host: 127.0.0.1
# port: 27017
# database: ecommerce_db
# username: ecommerce_user
# password: ecommerce123
# authentication-database: ecommerce_db
# 连接池优化(Spring Data MongoDB默认使用MongoDB Java Driver的连接池)
mongodb:
driver:
core:
connection-pool:
max-size: 100 # 最大连接数
min-size: 10 # 最小空闲连接数
max-wait-time: 3000ms # 最大等待时间
max-connection-life-time: 3600000ms # 连接最大生命周期
# 日志配置(开发环境打印MongoDB操作日志)
logging:
level:
org.springframework.data.mongodb.core: DEBUG
3. 核心概念与实体类映射
MongoDB 的核心概念与关系型数据库的对应关系如下:
- 数据库(Database):对应关系型数据库的数据库。
- 集合(Collection):对应关系型数据库的表。
- 文档(Document):对应关系型数据库的行。
- 字段(Field):对应关系型数据库的列。
- 索引(Index):与关系型数据库索引功能一致,用于提升查询性能。
(1)实体类注解说明
Spring Data MongoDB 通过注解实现实体类与 MongoDB 文档的映射,这些注解的详细用法是学习 Spring Data MongoDB 官方文档 的重要部分:
@Document(collection = “集合名”):指定实体类对应 MongoDB 的集合。
@Id:指定文档的主键(_id 字段)。
@Field(name = “字段名”):指定实体类字段与文档字段的映射关系(可自定义文档字段名)。
@Indexed:为该字段创建索引。
@Transient:忽略该字段,不存入 MongoDB。
@DateTimeFormat:日期时间格式化。
(2)实体类定义(用户行为日志、商品评论)
package com.example.mongodb.entity;
import lombok.Data;
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.index.Indexed;
import org.springframework.data.mongodb.core.mapping.Document;
import org.springframework.data.mongodb.core.mapping.Field;
import java.time.LocalDateTime;
import java.util.Map;
/**
* 用户行为日志实体(非结构化数据示例)
*/
@Data
@Document(collection = “user_behavior”) // 对应MongoDB的user_behavior集合
public class UserBehavior {
@Id // 主键(MongoDB自动生成ObjectId)
private String id;
@Indexed // 为userId创建索引,提升查询性能
@Field(name = “user_id”) // 文档字段名:user_id
private Long userId;
@Field(name = “behavior_type”) // 行为类型:browse(浏览)、click(点击)、order(下单)
private String behaviorType;
@Field(name = “goods_id”) // 关联商品ID
private Long goodsId;
@Field(name = “behavior_time”) // 行为时间
private LocalDateTime behaviorTime;
@Field(name = “ext_info”) // 扩展信息(灵活存储不同行为的额外字段)
private Map<String, Object> extInfo; // 非结构化字段,存储动态数据
}
/**
* 商品评论实体(半结构化数据示例,包含地理空间信息)
*/
@Data
@Document(collection = “goods_comment”)
public class GoodsComment {
@Id
private String id;
@Field(name = “goods_id”)
@Indexed
private Long goodsId;
@Field(name = “user_id”)
private Long userId;
@Field(name = “user_name”)
private String userName;
@Field(name = “content”) // 评论内容
private String content;
@Field(name = “score”) // 评分(1-5)
@Indexed
private Integer score;
@Field(name = “comment_time”)
private LocalDateTime commentTime;
@Field(name = “location”) // 地理空间信息(经纬度)
private GeoPoint location; // 自定义地理坐标类
}
/**
* 地理坐标类(适配MongoDB的GeoJSON格式)
*/
@Data
public class GeoPoint {
@Field(name = “type”)
private String type = “Point”; // 类型:点
@Field(name = “coordinates”) // 经纬度:[经度, 纬度]
private double[] coordinates; // 示例:new double[]{120.12, 30.33}
}
4. Repository接口实现(简化CRUD)
Spring Data MongoDB 提供了 MongoRepository 接口,继承后即可获得默认的 CRUD 方法,无需手动编写代码。
(1)UserBehaviorRepository
package com.example.mongodb.repository;
import com.example.mongodb.entity.UserBehavior;
import org.springframework.data.mongodb.repository.MongoRepository;
import org.springframework.data.mongodb.repository.Query;
import java.time.LocalDateTime;
import java.util.List;
/**
* 用户行为日志Repository(继承MongoRepository)
*/
public interface UserBehaviorRepository extends MongoRepository<UserBehavior, String> {
// 1. 按方法名自动生成查询(Spring Data MongoDB自动解析方法名)
// 功能:查询指定用户、指定行为类型的行为日志,按时间倒序
List<UserBehavior> findByUserIdAndBehaviorTypeOrderByBehaviorTimeDesc(Long userId, String behaviorType);
// 2. 按时间范围查询
List<UserBehavior> findByBehaviorTimeBetween(LocalDateTime start, LocalDateTime end);
// 3. 自定义查询(使用@Query注解,编写MongoDB查询语句)
// 功能:查询指定商品的浏览行为,只返回userId和behaviorTime字段
@Query(value = “{ ‘goods_id’ : ?0, ‘behavior_type’ : ‘browse’ }”, fields = “{ ‘user_id’ : 1, ‘behavior_time’ : 1 }”)
List<UserBehavior> findBrowseBehaviorByGoodsId(Long goodsId);
}
package com.example.mongodb.repository;
import com.example.mongodb.entity.GoodsComment;
import org.springframework.data.mongodb.repository.MongoRepository;
import org.springframework.data.mongodb.repository.Query;
import java.util.List;
/**
* 商品评论Repository
*/
public interface GoodsCommentRepository extends MongoRepository<GoodsComment, String> {
// 按商品ID查询评论,按时间倒序
List<GoodsComment> findByGoodsIdOrderByCommentTimeDesc(Long goodsId);
// 按评分查询指定商品的评论
List<GoodsComment> findByGoodsIdAndScore(Long goodsId, Integer score);
// 自定义查询:查询评分大于等于指定分数的评论
@Query(value = “{ ‘goods_id’ : ?0, ‘score’ : { $gte : ?1 } }”)
List<GoodsComment> findHighScoreCommentByGoodsId(Long goodsId, Integer minScore);
}
5. Service层实现(业务逻辑封装)
封装 Repository 接口,实现核心业务逻辑:
package com.example.mongodb.service;
import com.example.mongodb.entity.UserBehavior;
import com.example.mongodb.entity.GoodsComment;
import com.example.mongodb.repository.UserBehaviorRepository;
import com.example.mongodb.repository.GoodsCommentRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;
import java.time.LocalDateTime;
import java.util.List;
@Service
@RequiredArgsConstructor
public class MongoDbService {
private final UserBehaviorRepository userBehaviorRepository;
private final GoodsCommentRepository goodsCommentRepository;
// ——————- 用户行为日志相关 ——————-
// 新增用户行为日志
public UserBehavior saveUserBehavior(UserBehavior userBehavior) {
userBehavior.setBehaviorTime(LocalDateTime.now()); // 自动填充时间
return userBehaviorRepository.save(userBehavior);
}
// 分页查询用户行为日志
public Page<UserBehavior> getUserBehaviorByPage(Long userId, int pageNum, int pageSize) {
// 按时间倒序排序
Sort sort = Sort.by(Sort.Direction.DESC, “behaviorTime”);
Pageable pageable = PageRequest.of(pageNum – 1, pageSize, sort);
return userBehaviorRepository.findByUserId(userId, pageable);
}
// 查询指定商品的浏览行为
public List<UserBehavior> getBrowseBehaviorByGoodsId(Long goodsId) {
return userBehaviorRepository.findBrowseBehaviorByGoodsId(goodsId);
}
// ——————- 商品评论相关 ——————-
// 新增商品评论
public GoodsComment saveGoodsComment(GoodsComment goodsComment) {
goodsComment.setCommentTime(LocalDateTime.now());
return goodsCommentRepository.save(goodsComment);
}
// 分页查询商品评论
public Page<GoodsComment> getGoodsCommentByPage(Long goodsId, int pageNum, int pageSize) {
Sort sort = Sort.by(Sort.Direction.DESC, “commentTime”);
Pageable pageable = PageRequest.of(pageNum – 1, pageSize, sort);
return goodsCommentRepository.findByGoodsId(goodsId, pageable);
}
// 查询指定商品的高分评论(>=4分)
public List<GoodsComment> getHighScoreComment(Long goodsId) {
return goodsCommentRepository.findHighScoreCommentByGoodsId(goodsId, 4);
}
}
6. Controller层实现(提供API接口)
package com.example.mongodb.controller;
import com.example.mongodb.entity.UserBehavior;
import com.example.mongodb.entity.GoodsComment;
import com.example.mongodb.service.MongoDbService;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Page;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@RequestMapping(“/api/mongodb”)
@RequiredArgsConstructor
public class MongoDbController {
private final MongoDbService mongoDbService;
// ——————- 用户行为日志接口 ——————-
@PostMapping(“/behavior”)
public ResponseEntity<UserBehavior> saveUserBehavior(@RequestBody UserBehavior userBehavior) {
UserBehavior saved = mongoDbService.saveUserBehavior(userBehavior);
return ResponseEntity.ok(saved);
}
@GetMapping(“/behavior/user/{userId}”)
public ResponseEntity<Page<UserBehavior>> getUserBehavior(
@PathVariable Long userId,
@RequestParam(defaultValue = “1”) int pageNum,
@RequestParam(defaultValue = “10”) int pageSize) {
Page<UserBehavior> page = mongoDbService.getUserBehaviorByPage(userId, pageNum, pageSize);
return ResponseEntity.ok(page);
}
@GetMapping(“/behavior/goods/{goodsId}/browse”)
public ResponseEntity<List<UserBehavior>> getBrowseBehavior(@PathVariable Long goodsId) {
List<UserBehavior> list = mongoDbService.getBrowseBehaviorByGoodsId(goodsId);
return ResponseEntity.ok(list);
}
// ——————- 商品评论接口 ——————-
@PostMapping(“/comment”)
public ResponseEntity<GoodsComment> saveGoodsComment(@RequestBody GoodsComment goodsComment) {
GoodsComment saved = mongoDbService.saveGoodsComment(goodsComment);
return ResponseEntity.ok(saved);
}
@GetMapping(“/comment/goods/{goodsId}”)
public ResponseEntity<Page<GoodsComment>> getGoodsComment(
@PathVariable Long goodsId,
@RequestParam(defaultValue = “1”) int pageNum,
@RequestParam(defaultValue = “10”) int pageSize) {
Page<GoodsComment> page = mongoDbService.getGoodsCommentByPage(goodsId, pageNum, pageSize);
return ResponseEntity.ok(page);
}
@GetMapping(“/comment/goods/{goodsId}/high-score”)
public ResponseEntity<List<GoodsComment>> getHighScoreComment(@PathVariable Long goodsId) {
List<GoodsComment> list = mongoDbService.getHighScoreComment(goodsId);
return ResponseEntity.ok(list);
}
}
四、高级查询:聚合查询与地理空间查询
MongoDB 的强大之处在于其原生支持复杂的聚合查询和地理空间查询,这使其特别适合数据分析和位置相关的业务场景。
1. 聚合查询(Aggregation)
聚合查询用于对集合数据进行多阶段的统计分析(如分组、筛选、排序、计算)。Spring Data MongoDB 通过 Aggregation 类封装了聚合管道操作。
(1)聚合查询场景1:用户行为统计(按行为类型分组计数)
需求:统计指定用户的各类行为数量(如浏览、点击、下单次数)。
package com.example.mongodb.service;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.aggregation.Aggregation;
import org.springframework.data.mongodb.core.aggregation.AggregationResults;
import org.springframework.data.mongodb.core.aggregation.GroupOperation;
import org.springframework.data.mongodb.core.aggregation.MatchOperation;
import org.springframework.stereotype.Service;
import lombok.RequiredArgsConstructor;
import java.util.Map;
@Service
@RequiredArgsConstructor
public class AggregationService {
private final MongoTemplate mongoTemplate; // 用于复杂查询的核心模板类
/**
* 统计指定用户的各类行为数量
*/
public Map<String, Long> statUserBehaviorCount(Long userId) {
// 1. 匹配条件:筛选指定用户的行为日志
MatchOperation match = Aggregation.match(Criteria.where(“user_id”).is(userId));
// 2. 分组:按行为类型分组,计数
GroupOperation group = Aggregation.group(“behavior_type”)
.count().as(“count”); // 计数结果字段名:count
// 3. 构建聚合管道
Aggregation aggregation = Aggregation.newAggregation(match, group);
// 4. 执行聚合查询
AggregationResults<BehaviorStatDTO> results = mongoTemplate.aggregate(
aggregation,
“user_behavior”, // 目标集合
BehaviorStatDTO.class // 结果映射的DTO类
);
// 5. 转换结果为Map(key:行为类型,value:数量)
return results.getMappedResults().stream()
.collect(Collectors.toMap(
BehaviorStatDTO::getBehaviorType,
BehaviorStatDTO::getCount
));
}
// 结果DTO类
@Data
public static class BehaviorStatDTO {
private String behaviorType;
private Long count;
}
}
(2)聚合查询场景2:商品评论评分统计(按评分分组计算占比)
需求:统计指定商品的评论评分分布(如5分占比、4分占比等)。
/**
* 统计指定商品的评论评分分布
*/
public Map<Integer, Double> statGoodsCommentScore(Long goodsId) {
// 1. 匹配条件:筛选指定商品的评论
MatchOperation match = Aggregation.match(Criteria.where(“goods_id”).is(goodsId));
// 2. 分组:按评分分组,计数
GroupOperation groupByScore = Aggregation.group(“score”)
.count().as(“scoreCount”);
// 3. 计算总评论数(子聚合)
GroupOperation groupTotal = Aggregation.group()
.push(“$$ROOT”).as(“scoreList”) // 保存分组结果
.count().as(“totalCount”); // 总评论数
// 4. 展开scoreList(便于后续计算占比)
UnwindOperation unwind = Aggregation.unwind(“scoreList”);
// 5. 计算占比(scoreCount / totalCount)
ProjectionOperation project = Aggregation.project()
.and(“scoreList.score”).as(“score”)
.andExpression(“round( (scoreList.scoreCount / totalCount) * 100, 2 )”).as(“rate”); // 保留2位小数
// 6. 构建聚合管道
Aggregation aggregation = Aggregation.newAggregation(
match, groupByScore, groupTotal, unwind, project
);
// 7. 执行查询并转换结果
AggregationResults<ScoreRateDTO> results = mongoTemplate.aggregate(
aggregation, “goods_comment”, ScoreRateDTO.class
);
return results.getMappedResults().stream()
.collect(Collectors.toMap(
ScoreRateDTO::getScore,
ScoreRateDTO::getRate
));
}
// 评分占比DTO
@Data
public static class ScoreRateDTO {
private Integer score;
private Double rate; // 占比(百分比)
}
2. 地理空间查询
MongoDB 原生支持地理空间索引和查询,适合“附近的人”、“附近的评论”、“范围检索”等场景。其核心是依赖 GeoJSON 格式来存储地理坐标(如 Point 点、Polygon 多边形)。
(1)创建地理空间索引
首先需要为 goods_comment 集合的 location 字段创建 2dsphere 索引(支持球面地理空间查询):
package com.example.mongodb.config;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.index.GeospatialIndex;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import lombok.RequiredArgsConstructor;
/**
* MongoDB索引配置(地理空间索引)
*/
@Component
@RequiredArgsConstructor
public class MongoIndexConfig {
private final MongoTemplate mongoTemplate;
@PostConstruct
public void createIndex() {
// 为goods_comment集合的location字段创建2dsphere索引
mongoTemplate.indexOps(“goods_comment”)
.ensureIndex(new GeospatialIndex(“location”));
System.out.println(“MongoDB地理空间索引创建完成”);
}
}
(2)地理空间查询场景1:查询指定位置附近的商品评论
需求:查询距离指定经纬度(如经度120.12,纬度30.33)5公里范围内的商品评论,按距离升序排序。
package com.example.mongodb.service;
import com.example.mongodb.entity.GoodsComment;
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 lombok.RequiredArgsConstructor;
import java.util.List;
@Service
@RequiredArgsConstructor
public class GeoSpatialService {
private final MongoTemplate mongoTemplate;
/**
* 查询指定位置附近的商品评论
* @param longitude 经度
* @param latitude 纬度
* @param distance 距离(单位:米)
* @return 评论列表(按距离升序)
*/
public List<GoodsComment> findNearbyComments(double longitude, double latitude, double distance) {
// 1. 构建地理空间查询条件:查询指定点附近的文档
Criteria criteria = Criteria.where(“location”)
.nearSphere(Criteria.where(“location”)
.geometry(new GeoJsonPoint(longitude, latitude))) // 中心点
.maxDistance(distance); // 最大距离(米)
// 2. 构建查询对象,按距离升序排序
Query query = Query.query(criteria)
.with(Sort.by(Sort.Direction.ASC, “distance”)); // 按距离升序
// 3. 执行查询
return mongoTemplate.find(query, GoodsComment.class, “goods_comment”);
}
}
(3)地理空间查询场景2:查询指定区域内的商品评论
需求:查询位于指定多边形区域内的商品评论(例如某个城市的特定区域)。
/**
* 查询指定多边形区域内的商品评论
* @param polygonCoordinates 多边形顶点经纬度(格式:[[x1,y1],[x2,y2],...,[x1,y1]])
* @return 评论列表
*/
public List<GoodsComment> findCommentsInPolygon(List<double[]> polygonCoordinates) {
// 1. 构建多边形GeoJSON对象
GeoJsonPolygon polygon = new GeoJsonPolygon(polygonCoordinates);
// 2. 构建查询条件:文档的location在多边形内
Criteria criteria = Criteria.where(“location”)
.within(polygon);
// 3. 执行查询
Query query = Query.query(criteria);
return mongoTemplate.find(query, GoodsComment.class, “goods_comment”);
}
五、关键优化与问题解决
1. 性能优化核心要点
- 索引优化:为高频查询字段(如
userId、goodsId、score)创建索引,地理空间查询必须创建 2dsphere 索引。
- 连接池优化:根据实际并发量调整最大连接数、最小空闲连接数,避免连接耗尽。
- 查询优化:
- 避免查询不必要的字段(使用
fields 指定返回字段)。
- 大集合查询务必使用分页,避免一次性加载大量数据。
- 复杂查询优先使用聚合管道,减少客户端与数据库的交互次数。
- 数据分片:在海量数据场景下,应使用 MongoDB 分片集群(Sharding),按分片键拆分数据,以提升横向扩展和并发处理能力。
2. 常见问题与解决方案
- 数据一致性问题:MongoDB 默认是最终一致性。在单节点部署下,可通过
writeConcern(写关注)来保证写入的持久化(例如 w: 1 表示等待主节点确认写入)。
- 索引失效问题:查询条件中如果使用了字段类型转换、正则匹配(如
/xxx/)可能导致索引失效,需要合理设计查询条件。
- 地理空间查询精度问题:确保存储的经纬度格式正确(
[经度, 纬度]),并使用 2dsphere 索引而非 2d 索引(2d 索引适用于平面坐标,精度较低)。
- 大文档处理:避免存储过大的文档(建议单文档小于 16MB),可以拆分大文档为多个小文档,通过关联字段进行关联。
3. 高可用部署建议
生产环境中,为避免 MongoDB 单点故障,推荐部署主从复制+哨兵或MongoDB 副本集(Replica Set):
- 副本集(Replica Set):包含 1 个主节点(Primary)和多个从节点(Secondary)。主节点负责写操作,从节点同步主节点数据并提供读服务。当主节点故障时,集群会自动选举出新的主节点。
- 配置调整:Spring Boot 连接副本集时,需要修改 MongoDB 连接 URI,格式例如:
mongodb://user:password@host1:port1,host2:port2,host3:port3/db?replicaSet=副本集名称&authSource=db。