从0到1精通Mongo-Plus:核心模块深度解析与实战指南
【免费下载链接】mongo-plus 🔥🔥🔥使用MyBatisPlus的方式,优雅的操作MongoDB 项目地址: https://gitcode.com/aizuda/mongo-plus
引言:MongoDB开发的痛点与解决方案
你是否还在为MongoDB复杂的查询语法而头疼?是否在寻找一种像MyBatis-Plus操作关系型数据库那样优雅的方式来操作MongoDB?Mongo-Plus(MongoDB增强工具包)正是为解决这些问题而生。本文将带你深入探索Mongo-Plus的核心模块,掌握其设计理念与使用方法,让你的MongoDB开发效率提升10倍!
读完本文,你将获得:
- 全面了解Mongo-Plus的架构设计与核心模块
- 掌握条件构造器的高级用法与查询优化技巧
- 学会使用聚合操作实现复杂数据分析
- 理解并应用Mongo-Plus的事务与数据安全机制
- 精通自定义扩展与性能调优的实用方法
1. Mongo-Plus整体架构概览
Mongo-Plus采用分层设计,核心模块之间既相互独立又协同工作,为开发者提供了一站式的MongoDB操作解决方案。
1.1 架构设计图
1.2 核心模块功能矩阵
| 模块名称 | 主要功能 | 核心类 | 典型应用场景 |
|---|---|---|---|
| 条件构造模块 | 构建查询条件、更新条件 | QueryWrapper, UpdateWrapper | 数据查询、更新操作 |
| 聚合操作模块 | 实现MongoDB聚合管道 | AggregateWrapper, Accumulators | 统计分析、数据报表 |
| 映射转换模块 | Java对象与BSON文档转换 | MongoConverter, TypeHandler | ORM映射、类型处理 |
| 事务管理模块 | 支持事务操作 | TransactionHandler, MongoTransactional | 数据一致性保障 |
| 数据安全模块 | 数据加密、脱敏 | Encryptor, DesensitizationHandler | 敏感信息保护 |
| 扩展机制模块 | 提供拦截、自定义处理 | Interceptor, MetaObjectHandler | 业务逻辑增强 |
| 基础支持模块 | 工具类、异常处理等基础设施 | MongoUtil, MongoPlusException | 通用功能支持 |
2. 条件构造模块深度解析
条件构造模块是Mongo-Plus的核心,提供了强大而灵活的查询条件构建能力,支持链式编程,极大简化了MongoDB查询的编写。
2.1 核心类层次结构
2.2 条件构造器使用详解
2.2.1 基本查询条件构建
Mongo-Plus提供了两种风格的条件构造器:传统字符串列名方式和Lambda表达式方式。Lambda方式可以提供更好的类型安全和代码提示。
传统方式示例:
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("name", "张三")
.ne("status", 0)
.gt("age", 18)
.like("email", "@qq.com")
.between("create_time", "2023-01-01", "2023-12-31")
.orderByDesc("create_time")
.select("id", "name", "age", "email");
List<User> userList = userMapper.selectList(queryWrapper);
Lambda方式示例:
LambdaQueryWrapper<User> lambdaQuery = new LambdaQueryWrapper<>();
lambdaQuery.eq(User::getName, "张三")
.ne(User::getStatus, 0)
.gt(User::getAge, 18)
.like(User::getEmail, "@qq.com")
.between(User::getCreateTime, "2023-01-01", "2023-12-31")
.orderByDesc(User::getCreateTime)
.select(User::getId, User::getName, User::getAge, User::getEmail);
List<User> userList = userMapper.selectList(lambdaQuery);
2.2.2 高级查询功能
组合条件与嵌套查询:
LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(User::getStatus, 1)
.and(wq -> wq.gt(User::getAge, 18).or().like(User::getEmail, "@admin.com"))
.or(wq -> wq.eq(User::getVipLevel, 3).ge(User::getCreateTime, "2023-01-01"))
.nested(wq -> wq.isNotNull(User::getPhone).ne(User::getPhone, ""));
子查询示例:
LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.inSql(User::getId, "SELECT user_id FROM user_role WHERE role_id = 1");
Exists查询:
LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.exists("SELECT 1 FROM orders WHERE orders.user_id = user.id AND orders.status = 1");
2.2.3 更新条件构建
基本更新:
UpdateWrapper<User> updateWrapper = new UpdateWrapper<>();
updateWrapper.eq("id", 1)
.set("name", "张三更新")
.set("age", 25)
.inc("login_count", 1);
int rows = userMapper.update(null, updateWrapper);
Lambda更新:
LambdaUpdateWrapper<User> lambdaUpdate = new LambdaUpdateWrapper<>();
lambdaUpdate.eq(User::getId, 1)
.set(User::getName, "张三更新")
.set(User::getAge, 25)
.inc(User::getLoginCount, 1);
int rows = userMapper.update(null, lambdaUpdate);
条件更新:
LambdaUpdateWrapper<User> lambdaUpdate = new LambdaUpdateWrapper<>();
lambdaUpdate.eq(User::getStatus, 1)
.setSql("age = age + 1")
.set(User::getUpdateTime, new Date());
int rows = userMapper.update(null, lambdaUpdate);
2.3 查询优化技巧
2.3.1 投影查询(只返回需要的字段)
LambdaQueryWrapper<User> lambdaQuery = new LambdaQueryWrapper<>();
lambdaQuery.eq(User::getId, 1)
.select(User::getId, User::getName, User::getEmail);
2.3.2 分页查询
PageParam pageParam = new PageParam();
pageParam.setPageNum(1); // 页码,从1开始
pageParam.setPageSize(10); // 每页条数
LambdaQueryWrapper<User> lambdaQuery = new LambdaQueryWrapper<>();
lambdaQuery.eq(User::getStatus, 1)
.orderByDesc(User::getCreateTime);
PageResult<User> pageResult = userMapper.selectPage(pageParam, lambdaQuery);
// 分页结果信息
long total = pageResult.getTotalSize(); // 总记录数
long pages = pageResult.getTotalPages(); // 总页数
List<User> records = pageResult.getContentData(); // 当前页数据
2.3.3 性能监控与分析
Mongo-Plus提供了查询性能监控功能,可以通过拦截器记录慢查询:
@Configuration
public class MongoPlusConfig {
@Bean
public PerformanceInterceptor performanceInterceptor() {
PerformanceInterceptor interceptor = new PerformanceInterceptor();
interceptor.setMaxTime(100); // 设置慢查询阈值,单位毫秒
interceptor.setFormat(true); // 是否格式化SQL
return interceptor;
}
}
3. 聚合操作模块详解
Mongo-Plus的聚合操作模块提供了强大而直观的API,简化了MongoDB聚合管道的构建过程,支持复杂的数据统计分析需求。
3.1 聚合操作核心组件
Mongo-Plus的聚合模块主要包含以下核心类:
- AggregateWrapper: 聚合操作的入口类,用于构建完整的聚合管道
- LambdaAggregateWrapper: Lambda风格的聚合构造器,提供类型安全的聚合操作
- Accumulators: 聚合累加器工具类,提供各种聚合操作函数
- AggregateOperator: 聚合操作符工具类,提供各种管道操作符
3.2 常用聚合操作示例
3.2.1 基本聚合示例:用户订单统计
// 统计每个用户的订单数量和总金额
LambdaAggregateWrapper<User> aggregateWrapper = new LambdaAggregateWrapper<>();
aggregateWrapper.lookup(Order.class, User::getId, Order::getUserId, "orders")
.unwind("orders")
.groupBy(User::getId)
.groupBy(User::getName)
.count("orderCount")
.sum("orders.totalAmount", "totalAmount")
.project("id", "name", "orderCount", "totalAmount");
List<Map<String, Object>> result = userMapper.aggregateList(aggregateWrapper);
3.2.2 复杂聚合示例:商品销售分析
LambdaAggregateWrapper<Order> aggregateWrapper = new LambdaAggregateWrapper<>();
aggregateWrapper.match(new QueryWrapper<Order>()
.between("create_time", "2023-01-01", "2023-12-31"))
.groupBy("product_id")
.sum("quantity", "totalQuantity")
.sum("totalAmount", "totalSales")
.avg("unitPrice", "avgPrice")
.max("create_time", "lastSaleTime")
.lookup(Product.class, "product_id", "_id", "product")
.unwind("product")
.project(Projections.fields(
Projections.excludeId(),
Projections.include("product_id", "totalQuantity", "totalSales", "avgPrice", "lastSaleTime"),
Projections.computed("product.name", "productName")
))
.sort(Sorts.desc("totalSales"))
.limit(10);
List<Map<String, Object>> topProducts = orderMapper.aggregateList(aggregateWrapper);
3.3 高级聚合操作
3.3.1 多阶段聚合管道
LambdaAggregateWrapper<Order> aggregateWrapper = new LambdaAggregateWrapper<>();
// 阶段1: 匹配条件
aggregateWrapper.match(new QueryWrapper<Order>().eq("status", 1))
// 阶段2: 分组统计
.groupBy("user_id")
.sum("totalAmount", "totalSpent")
.count("orderCount")
// 阶段3: 关联用户信息
.lookup(User.class, "user_id", "_id", "userInfo")
.unwind("userInfo")
// 阶段4: 投影需要的字段
.project(Projections.fields(
Projections.excludeId(),
Projections.include("user_id", "totalSpent", "orderCount"),
Projections.computed("userInfo.name", "userName"),
Projections.computed("userInfo.email", "userEmail")
))
// 阶段5: 筛选高价值用户
.match(new QueryWrapper<Map>().gt("totalSpent", 1000))
// 阶段6: 排序
.sort(Sorts.desc("totalSpent"))
// 阶段7: 限制结果数量
.limit(20);
3.3.2 使用累加器进行复杂计算
Mongo-Plus的Accumulators类提供了丰富的聚合累加器函数:
LambdaAggregateWrapper<Order> aggregateWrapper = new LambdaAggregateWrapper<>();
aggregateWrapper.groupBy("product_id")
.sum("quantity", "totalQuantity")
.sum("totalAmount", "totalSales")
.avg("unitPrice", "avgPrice")
.max("unitPrice", "maxPrice")
.min("unitPrice", "minPrice")
.push("orderDate", "orderDates")
.addToSet("userId", "customerIds")
.first("productName", "productName");
3.3.3 条件聚合与分支处理
使用AggregationOperators.cond实现条件聚合:
LambdaAggregateWrapper<Order> aggregateWrapper = new LambdaAggregateWrapper<>();
aggregateWrapper.groupBy("user_id")
.sum("totalAmount", "totalSpent")
.count("orderCount")
.addFields("customerLevel",
AggregationOperators.cond(
ConditionalOperators.gt("totalSpent", 10000),
"VIP",
ConditionalOperators.cond(
ConditionalOperators.gt("totalSpent", 5000),
"Gold",
"Silver"
)
)
);
3.4 聚合结果处理
Mongo-Plus提供了多种聚合结果处理方式:
3.4.1 聚合结果映射到实体类
@Data
public class UserOrderSummary {
private String userId;
private String userName;
private Integer orderCount;
private BigDecimal totalAmount;
}
LambdaAggregateWrapper<User> aggregateWrapper = new LambdaAggregateWrapper<>();
// ... 构建聚合管道
List<UserOrderSummary> result = userMapper.aggregateList(aggregateWrapper, UserOrderSummary.class);
3.4.2 聚合分页查询
PageParam pageParam = new PageParam();
pageParam.setPageNum(1);
pageParam.setPageSize(10);
LambdaAggregateWrapper<Order> aggregateWrapper = new LambdaAggregateWrapper<>();
// ... 构建聚合管道
PageResult<Map<String, Object>> pageResult = orderMapper.aggregatePage(pageParam, aggregateWrapper);
4. 映射转换模块
映射转换模块是Mongo-Plus实现ORM(对象关系映射)功能的核心,负责Java对象与MongoDB BSON文档之间的双向转换。
4.1 核心转换机制
Mongo-Plus的映射转换基于以下核心组件:
- MongoConverter: 顶层转换接口,定义了Java对象与BSON文档之间的转换方法
- MappingMongoConverter: 默认转换器实现,提供基本的类型转换功能
- TypeHandler: 类型处理器接口,用于自定义特定类型的转换逻辑
- FieldHandler: 字段处理器接口,用于自定义字段级别的处理逻辑
4.2 自定义类型转换器
当Mongo-Plus内置的类型转换器无法满足需求时,我们可以自定义类型转换器:
4.2.1 自定义日期类型转换器
@Component
public class CustomDateTypeHandler implements TypeHandler<LocalDateTime> {
private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
@Override
public Object getParameter(LocalDateTime parameter) {
// Java对象转BSON值
return parameter == null ? null : Date.from(parameter.atZone(ZoneId.systemDefault()).toInstant());
}
@Override
public LocalDateTime getResult(Object result) {
// BSON值转Java对象
if (result == null) {
return null;
}
if (result instanceof Date) {
return ((Date) result).toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();
}
if (result instanceof String) {
return LocalDateTime.parse((String) result, FORMATTER);
}
throw new TypeConvertException("Unsupported type conversion from " + result.getClass() + " to LocalDateTime");
}
}
4.2.2 注册自定义类型转换器
@Configuration
public class MongoPlusConfig {
@Bean
public MongoConverter mongoConverter() {
MappingMongoConverter converter = new MappingMongoConverter();
// 注册自定义类型转换器
converter.getTypeHandlerRegistry().register(LocalDateTime.class, new CustomDateTypeHandler());
return converter;
}
}
4.3 字段级自定义处理
Mongo-Plus提供了字段级别的自定义处理机制,可以通过注解或自定义FieldHandler实现:
4.3.1 使用注解进行字段处理
@Data
@Document("user")
public class User {
@Id
private String id;
private String name;
@Field("user_age")
private Integer age;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date createTime;
@EncryptField(type = EncryptType.AES)
private String idCard;
@SensitiveField(type = SensitiveType.PHONE)
private String phone;
}
4.3.2 自定义字段处理器
@Component
public class CustomFieldHandler implements FieldHandler {
@Override
public Object process(Object value, Field field, Document document) {
if (field.getName().equals("password") && value != null) {
// 对密码进行加密处理
return PasswordUtils.encode((String) value);
}
return value;
}
}
4.4 高级映射功能
4.4.1 嵌套对象映射
Mongo-Plus支持复杂对象的嵌套映射:
@Data
@Document("order")
public class Order {
@Id
private String id;
private String orderNo;
private User buyer; // 嵌套User对象
private List<OrderItem> items; // 嵌套集合
private BigDecimal totalAmount;
private Date createTime;
}
@Data
public class OrderItem {
private String productId;
private String productName;
private Integer quantity;
private BigDecimal unitPrice;
}
4.4.2 枚举类型映射
Mongo-Plus提供了灵活的枚举类型映射机制:
// 枚举定义
public enum OrderStatus {
PENDING(0, "待支付"),
PAID(1, "已支付"),
SHIPPED(2, "已发货"),
DELIVERED(3, "已送达"),
CANCELLED(4, "已取消");
private final int code;
private final String desc;
// 构造函数、getter等省略
}
// 实体类中使用
@Data
@Document("order")
public class Order {
@Id
private String id;
private String orderNo;
@EnumValue // 存储枚举的code值
private OrderStatus status;
// 其他字段省略
}
5. 事务与数据安全模块
Mongo-Plus提供了完善的事务支持和数据安全保障机制,确保数据操作的一致性和安全性。
5.1 事务管理
Mongo-Plus支持两种事务模式:本地事务和分布式事务。
5.1.1 本地事务使用
@Service
public class OrderService {
@Autowired
private OrderMapper orderMapper;
@Autowired
private OrderItemMapper orderItemMapper;
@Transactional
public void createOrder(Order order, List<OrderItem> items) {
// 保存订单
orderMapper.insert(order);
// 保存订单项
for (OrderItem item : items) {
item.setOrderId(order.getId());
orderItemMapper.insert(item);
}
// 更新商品库存
// ...
}
}
5.1.2 事务配置
@Configuration
public class TransactionConfig {
@Bean
public TransactionManager transactionManager(MongoDatabaseFactory dbFactory) {
MongoTransactionManager transactionManager = new MongoTransactionManager();
transactionManager.setDbFactory(dbFactory);
transactionManager.setDefaultTimeout(60); // 设置默认超时时间,单位秒
return transactionManager;
}
}
5.1.3 分布式事务支持
Mongo-Plus通过集成Seata等分布式事务框架,支持跨多个MongoDB实例或混合数据库的分布式事务:
@Configuration
public class SeataConfig {
@Bean
public GlobalTransactionScanner globalTransactionScanner() {
return new GlobalTransactionScanner("mongo-plus-example", "my_test_tx_group");
}
}
@Service
public class OrderService {
@Autowired
private OrderMapper orderMapper;
@Autowired
private ProductMapper productMapper;
@GlobalTransactional // 分布式事务注解
public void createOrder(Order order, List<OrderItem> items) {
// 保存订单(MongoDB)
orderMapper.insert(order);
// 更新商品库存(MySQL)
for (OrderItem item : items) {
productMapper.decreaseStock(item.getProductId(), item.getQuantity());
}
}
}
5.2 数据安全机制
Mongo-Plus提供了多层次的数据安全保障机制,包括数据加密、脱敏、访问控制等。
5.2.1 数据加密
Mongo-Plus支持多种加密算法,可以对敏感数据进行加密存储:
@Configuration
public class EncryptConfig {
@Bean
public Encryptor aesEncryptor() {
AESEncryptor encryptor = new AESEncryptor();
encryptor.setKey("1234567890abcdef"); // 加密密钥
encryptor.setIv("abcdef1234567890"); // 初始化向量
return encryptor;
}
}
// 实体类中使用
@Data
@Document("user")
public class User {
@Id
private String id;
private String name;
@EncryptField(type = EncryptType.AES)
private String idCard;
@EncryptField(type = EncryptType.MD5)
private String password;
}
5.2.2 数据脱敏
Mongo-Plus支持多种数据脱敏策略,可以在查询时自动对敏感数据进行脱敏处理:
@Data
@Document("user")
public class User {
@Id
private String id;
private String name;
@SensitiveField(type = SensitiveType.PHONE)
private String phone;
@SensitiveField(type = SensitiveType.ID_CARD)
private String idCard;
@SensitiveField(type = SensitiveType.EMAIL)
private String email;
}
// 自定义脱敏策略
@Component
public class CustomSensitiveStrategy implements SensitiveStrategy {
@Override
public String desensitize(String value, SensitiveType type) {
if (type == SensitiveType.CUSTOM) {
if (value != null && value.length() > 4) {
return value.substring(0, 2) + "****" + value.substring(value.length() - 2);
}
}
return value;
}
}
5.2.3 乐观锁
Mongo-Plus提供了乐观锁支持,通过版本号机制实现并发控制:
@Data
@Document("product")
public class Product {
@Id
private String id;
private String name;
private Integer stock;
@Version
private Integer version; // 版本号字段
}
@Service
public class ProductService {
@Autowired
private ProductMapper productMapper;
public boolean decreaseStock(String productId, int quantity) {
Product product = productMapper.selectById(productId);
if (product.getStock() < quantity) {
return false;
}
UpdateWrapper<Product> updateWrapper = new UpdateWrapper<>();
updateWrapper.eq("id", productId)
.eq("version", product.getVersion()) // 乐观锁条件
.set("stock", product.getStock() - quantity)
.set("version", product.getVersion() + 1);
int rows = productMapper.update(null, updateWrapper);
return rows > 0;
}
}
6. 扩展机制与插件开发
Mongo-Plus提供了灵活的扩展机制,允许开发者通过拦截器、自定义处理器等方式扩展框架功能。
6.1 拦截器体系
Mongo-Plus的拦截器体系允许开发者在数据访问的各个阶段进行拦截和增强:
6.1.1 自定义查询拦截器
@Component
public class QueryInterceptor implements Interceptor {
@Override
public Object intercept(Invocation invocation) throws Throwable {
// 拦截查询操作
if (invocation.getMethod().getName().startsWith("select")) {
long startTime = System.currentTimeMillis();
// 执行原方法
Object result = invocation.proceed();
long endTime = System.currentTimeMillis();
long costTime = endTime - startTime;
// 记录慢查询
if (costTime > 100) {
log.warn("Slow query detected: {} ms, Method: {}",
costTime, invocation.getMethod().getName());
}
return result;
}
return invocation.proceed();
}
@Override
public Object plugin(Object target) {
// 只对Mapper接口应用拦截器
if (target instanceof Mapper) {
return Plugin.wrap(target, this);
}
return target;
}
}
6.1.2 分页拦截器
Mongo-Plus内置了分页拦截器,也可以自定义分页逻辑:
@Component
public class CustomPageInterceptor implements Interceptor {
@Override
public Object intercept(Invocation invocation) throws Throwable {
Method method = invocation.getMethod();
Object[] args = invocation.getArgs();
// 判断是否为分页查询方法
if (method.getName().equals("selectPage") && args.length >= 2
&& args[0] instanceof PageParam && args[1] instanceof QueryWrapper) {
PageParam pageParam = (PageParam) args[0];
QueryWrapper<?> queryWrapper = (QueryWrapper<?>) args[1];
// 添加分页信息到查询条件
long offset = (pageParam.getPageNum() - 1) * pageParam.getPageSize();
queryWrapper.last("LIMIT " + offset + ", " + pageParam.getPageSize());
// 先查询总数
long total = countTotal(queryWrapper);
// 执行查询
List<?> result = (List<?>) invocation.proceed();
// 构建分页结果
PageResult<?> pageResult = new PageResult<>();
pageResult.setContentData(result);
pageResult.setPageNum(pageParam.getPageNum());
pageResult.setPageSize(pageParam.getPageSize());
pageResult.setTotalSize(total);
pageResult.setTotalPages((total + pageParam.getPageSize() - 1) / pageParam.getPageSize());
return pageResult;
}
return invocation.proceed();
}
private long countTotal(QueryWrapper<?> queryWrapper) {
// 实现总数查询逻辑
// ...
}
}
6.2 自定义处理器
Mongo-Plus提供了多种处理器接口,可以通过实现这些接口来自定义特定功能:
6.2.1 自定义元对象处理器
元对象处理器用于实现自动填充等功能:
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {
@Override
public void insertFill(MetaObject metaObject) {
// 插入时自动填充创建时间
this.strictInsertFill(metaObject, "createTime", Date.class, new Date());
this.strictInsertFill(metaObject, "status", Integer.class, 1);
// 自动填充创建人
User currentUser = SecurityUtils.getCurrentUser();
if (currentUser != null) {
this.strictInsertFill(metaObject, "createBy", String.class, currentUser.getId());
}
}
@Override
public void updateFill(MetaObject metaObject) {
// 更新时自动填充更新时间
this.strictUpdateFill(metaObject, "updateTime", Date.class, new Date());
// 自动填充更新人
User currentUser = SecurityUtils.getCurrentUser();
if (currentUser != null) {
this.strictUpdateFill(metaObject, "updateBy", String.class, currentUser.getId());
}
}
}
6.2.2 自定义ID生成器
Mongo-Plus支持自定义ID生成策略:
@Component
public class SnowflakeIdGenerator implements IdentifierGenerator {
private final Snowflake snowflake = new Snowflake(1, 1);
@Override
public Object nextId(Object entity) {
// 使用雪花算法生成ID
return snowflake.nextIdStr();
}
}
@Configuration
public class MongoPlusConfig {
@Bean
public IdentifierGenerator idGenerator() {
return new SnowflakeIdGenerator();
}
}
6.3 插件开发最佳实践
6.3.1 插件开发规范
- 单一职责原则:一个插件只负责一项功能
- 配置化:插件应支持通过配置开启/关闭或调整行为
- 兼容性:考虑与其他插件的兼容性
- 性能影响:最小化插件对性能的影响
- 可测试性:设计时考虑可测试性
6.3.2 插件注册与排序
@Configuration
public class InterceptorConfig {
@Bean
public Interceptor[] interceptors() {
// 拦截器排序,按数组顺序执行
return new Interceptor[] {
new LogInterceptor(), // 日志拦截器
new PerformanceInterceptor(), // 性能监控拦截器
new DataScopeInterceptor() // 数据权限拦截器
};
}
}
7. 实战案例分析
7.1 电商订单系统设计
7.1.1 数据模型设计
// 用户模型
@Data
@Document("user")
public class User {
@Id
private String id;
private String username;
private String phone;
private String email;
private Integer status;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date createTime;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date updateTime;
}
// 商品模型
@Data
@Document("product")
public class Product {
@Id
private String id;
private String name;
private String categoryId;
private BigDecimal price;
private Integer stock;
private String imageUrl;
private Integer status;
@Version
private Integer version; // 乐观锁版本号
}
// 订单模型
@Data
@Document("order")
public class Order {
@Id
private String id;
private String orderNo;
private String userId;
private List<OrderItem> items;
private BigDecimal totalAmount;
private Integer status;
private String paymentMethod;
private Date payTime;
private Date deliveryTime;
private Date receiveTime;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date createTime;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date updateTime;
}
// 订单项模型
@Data
public class OrderItem {
private String productId;
private String productName;
private BigDecimal price;
private Integer quantity;
private BigDecimal totalPrice;
}
7.1.2 订单创建流程实现
@Service
public class OrderService {
@Autowired
private OrderMapper orderMapper;
@Autowired
private ProductMapper productMapper;
@Autowired
private InventoryService inventoryService;
@Transactional
public String createOrder(OrderCreateDTO orderDTO) {
// 1. 生成订单号
String orderNo = OrderNoGenerator.generate();
// 2. 扣减库存(使用乐观锁)
boolean inventoryResult = inventoryService.decreaseBatch(orderDTO.getItems());
if (!inventoryResult) {
throw new BusinessException("库存不足");
}
// 3. 创建订单
Order order = new Order();
order.setOrderNo(orderNo);
order.setUserId(orderDTO.getUserId());
order.setStatus(OrderStatus.PENDING.getValue());
order.setTotalAmount(calculateTotal(orderDTO.getItems()));
// 4. 设置订单项
List<OrderItem> items = orderDTO.getItems().stream().map(item -> {
OrderItem orderItem = new OrderItem();
orderItem.setProductId(item.getProductId());
orderItem.setProductName(item.getProductName());
orderItem.setPrice(item.getPrice());
orderItem.setQuantity(item.getQuantity());
orderItem.setTotalPrice(item.getPrice().multiply(new BigDecimal(item.getQuantity())));
return orderItem;
}).collect(Collectors.toList());
order.setItems(items);
// 5. 保存订单
orderMapper.insert(order);
// 6. 发送订单创建事件
eventPublisher.publishEvent(new OrderCreatedEvent(order));
return order.getId();
}
private BigDecimal calculateTotal(List<OrderItemDTO> items) {
return items.stream()
.map(item -> item.getPrice().multiply(new BigDecimal(item.getQuantity())))
.reduce(BigDecimal.ZERO, BigDecimal::add);
}
}
7.1.3 订单查询与统计分析
@Service
public class OrderStatisticsService {
@Autowired
private MongoTemplate mongoTemplate;
/**
* 统计用户订单情况
*/
public UserOrderStatsDTO statsUserOrders(String userId) {
LambdaAggregateWrapper<Order> aggregateWrapper = new LambdaAggregateWrapper<>();
aggregateWrapper.match(new QueryWrapper<Order>().eq("user_id", userId))
.groupBy("status")
.count("count")
.project("status", "count");
List<Map<String, Object>> result = mongoTemplate.aggregate(aggregateWrapper, Order.class);
UserOrderStatsDTO statsDTO = new UserOrderStatsDTO();
for (Map<String, Object> item : result) {
Integer status = (Integer) item.get("status");
Long count = (Long) item.get("count");
switch (OrderStatus.valueOf(status)) {
case PENDING:
statsDTO.setPendingCount(count.intValue());
break;
case PAID:
statsDTO.setPaidCount(count.intValue());
break;
case SHIPPED:
statsDTO.setShippedCount(count.intValue());
break;
case DELIVERED:
statsDTO.setDeliveredCount(count.intValue());
break;
case CANCELLED:
statsDTO.setCancelledCount(count.intValue());
break;
}
}
// 查询总消费金额
LambdaAggregateWrapper<Order> sumWrapper = new LambdaAggregateWrapper<>();
sumWrapper.match(new QueryWrapper<Order>().eq("user_id", userId)
.in("status", Arrays.asList(OrderStatus.PAID.getValue(),
OrderStatus.SHIPPED.getValue(),
OrderStatus.DELIVERED.getValue())))
.groupBy()
.sum("totalAmount", "totalSpent");
List<Map<String, Object>> sumResult = mongoTemplate.aggregate(sumWrapper, Order.class);
if (!sumResult.isEmpty()) {
BigDecimal totalSpent = (BigDecimal) sumResult.get(0).get("totalSpent");
statsDTO.setTotalSpent(totalSpent != null ? totalSpent : BigDecimal.ZERO);
}
return statsDTO;
}
/**
* 商品销售排行
*/
public List<ProductSalesDTO> productSalesRank(Date startTime, Date endTime, int limit) {
LambdaAggregateWrapper<Order> aggregateWrapper = new LambdaAggregateWrapper<>();
aggregateWrapper.match(new QueryWrapper<Order>()
.ge("create_time", startTime)
.le("create_time", endTime)
.eq("status", OrderStatus.DELIVERED.getValue()))
.unwind("items")
.groupBy("items.product_id")
.sum("items.quantity", "salesQuantity")
.sum("items.totalPrice", "salesAmount")
.project("items.product_id as productId", "salesQuantity", "salesAmount")
.sort(Sorts.desc("salesAmount"))
.limit(limit);
List<ProductSalesDTO> result = mongoTemplate.aggregate(aggregateWrapper, ProductSalesDTO.class);
// 补充商品名称
for (ProductSalesDTO dto : result) {
Product product = productMapper.selectById(dto.getProductId());
if (product != null) {
dto.setProductName(product.getName());
}
}
return result;
}
}
7.2 性能优化实践
7.2.1 索引优化
@Data
@Document("order")
@Indexes({
@Index(fields = "orderNo", unique = true),
@Index(fields = "userId"),
@Index(fields = "createTime"),
@Index(fields = "status,createTime")
})
public class Order {
// 字段定义省略
}
7.2.2 查询优化
@Service
public class OptimizedQueryService {
@Autowired
private MongoTemplate mongoTemplate;
/**
* 优化的订单查询
*/
public PageResult<Order> optimizedOrderQuery(OrderQueryDTO queryDTO, PageParam pageParam) {
// 1. 构建查询条件
LambdaQueryWrapper<Order> queryWrapper = new LambdaQueryWrapper<>();
// 2. 动态条件
if (StringUtils.isNotBlank(queryDTO.getUserId())) {
queryWrapper.eq(Order::getUserId, queryDTO.getUserId());
}
if (queryDTO.getStatus() != null) {
queryWrapper.eq(Order::getStatus, queryDTO.getStatus());
}
if (queryDTO.getStartTime() != null) {
queryWrapper.ge(Order::getCreateTime, queryDTO.getStartTime());
}
if (queryDTO.getEndTime() != null) {
queryWrapper.le(Order::getCreateTime, queryDTO.getEndTime());
}
// 3. 投影查询,只返回需要的字段
queryWrapper.select(Order::getId, Order::getOrderNo, Order::getUserId,
Order::getTotalAmount, Order::getStatus, Order::getCreateTime);
// 4. 排序优化
queryWrapper.orderByDesc(Order::getCreateTime);
// 5. 分页查询
PageResult<Order> pageResult = orderMapper.selectPage(pageParam, queryWrapper);
return pageResult;
}
/**
* 使用聚合管道优化关联查询
*/
public List<OrderDetailVO> getOrderDetails(String userId) {
// 使用聚合管道一次性完成关联查询,避免N+1问题
LambdaAggregateWrapper<Order> aggregateWrapper = new LambdaAggregateWrapper<>();
aggregateWrapper.match(new QueryWrapper<Order>().eq("user_id", userId))
.lookup(User.class, "user_id", "_id", "user")
.unwind("user")
.project(Projections.fields(
Projections.include("id", "orderNo", "totalAmount", "status", "createTime"),
Projections.computed("user.name", "userName"),
Projections.computed("user.phone", "userPhone")
));
return mongoTemplate.aggregate(aggregateWrapper, OrderDetailVO.class);
}
}
8. 总结与展望
8.1 核心功能回顾
Mongo-Plus作为一款MongoDB增强工具包,提供了以下核心功能:
- 强大的条件构造器:支持链式编程,提供Lambda风格API,简化查询条件构建
- 完善的聚合操作支持:提供直观的聚合管道构建API,支持复杂数据分析
- 灵活的映射转换机制:支持Java对象与BSON文档的双向转换,支持自定义类型转换
- 全面的事务支持:支持本地事务和分布式事务,保障数据一致性
- 多层次数据安全:提供数据加密、脱敏、访问控制等安全机制
- 丰富的扩展机制:支持拦截器、自定义处理器等多种扩展方式
- 高性能:通过优化查询、索引支持等方式提升数据访问性能
8.2 最佳实践总结
- 合理设计数据模型:充分利用MongoDB的文档模型特性,合理设计嵌套结构
- 优化索引策略:根据查询场景设计合适的索引,提升查询性能
- 使用投影查询:只返回需要的字段,减少数据传输和处理开销
- 批量操作优先:使用批量操作代替循环单个操作,提升性能
- 合理使用聚合管道:利用聚合管道减少客户端与数据库的交互次数
- 事务使用原则:只在必要时使用事务,平衡一致性与性能需求
- 监控与调优:使用Mongo-Plus提供的性能监控工具,持续优化数据访问性能
8.3 未来发展方向
- AI辅助查询优化:结合AI技术,自动分析和优化查询语句
- 更完善的分布式事务支持:支持跨多个MongoDB实例的分布式事务
- 实时数据分析:集成流处理能力,支持实时数据处理和分析
- 多数据源支持:支持MongoDB与其他数据库的混合使用
- 更丰富的可视化工具:提供更直观的查询构建和性能分析界面
Mongo-Plus作为一款活跃发展的开源项目,将持续吸收社区反馈,不断完善功能,为开发者提供更优雅、高效的MongoDB操作体验。
9. 附录:常用API速查表
9.1 条件构造器API
| 方法名 | 说明 | 示例 |
|---|---|---|
| eq | 等于 | eq("name", "张三") |
| ne | 不等于 | ne("status", 0) |
| gt | 大于 | gt("age", 18) |
| ge | 大于等于 | ge("score", 60) |
| lt | 小于 | lt("price", 100) |
| le | 小于等于 | le("stock", 10) |
| like | 模糊查询 | like("name", "%张%") |
| notLike | 不匹配模糊查询 | notLike("name", "%张%") |
| in | IN查询 | in("id", 1, 2, 3) |
| notIn | NOT IN查询 | notIn("status", 0, 2) |
| isNull | 为空 | isNull("email") |
| isNotNull | 不为空 | isNotNull("phone") |
| between | BETWEEN查询 | between("createTime", "2023-01-01", "2023-12-31") |
| notBetween | NOT BETWEEN查询 | notBetween("age", 18, 30) |
| and | AND条件 | and(i -> i.eq("name", "张三").ne("status", 0)) |
| or | OR条件 | or(i -> i.eq("status", 1).or().eq("status", 2)) |
| nested | 嵌套条件 | nested(i -> i.gt("age", 18).lt("age", 30)) |
| apply | 拼接SQL | apply("date_format(create_time, '%Y-%m-%d') = {0}", "2023-01-01") |
| orderByAsc | 升序排序 | orderByAsc("createTime") |
| orderByDesc | 降序排序 | orderByDesc("createTime") |
| select | 指定查询字段 | select("id", "name", "age") |
9.2 聚合操作API
| 方法名 | 说明 | 示例 |
|---|---|---|
| match | 过滤文档 | match(new QueryWrapper<>().eq("status", 1)) |
| groupBy | 分组 | groupBy("user_id") |
| sum | 求和 | sum("amount", "totalAmount") |
| count | 计数 | count("orderCount") |
| avg | 平均值 | avg("score", "avgScore") |
| max | 最大值 | max("price", "maxPrice") |
| min | 最小值 | min("price", "minPrice") |
| lookup | 关联查询 | lookup(User.class, "user_id", "_id", "user") |
| unwind | 展开数组 | unwind("items") |
| project | 投影 | project("id", "name", "age") |
| sort | 排序 | sort(Sorts.desc("createTime")) |
| skip | 跳过记录 | skip(10) |
| limit | 限制记录数 | limit(20) |
| addFields | 添加字段 | addFields("fullName", "$concat: ['$firstName', ' ', '$lastName']") |
| replaceRoot | 替换根文档 | replaceRoot("user") |
9.3 常用工具类
| 类名 | 说明 | 主要方法 |
|---|---|---|
| MongoUtil | MongoDB操作工具类 | getCollection(), executeCommand(), aggregate() |
| QueryUtil | 查询工具类 | buildQuery(), buildSort(), buildPage() |
| BsonUtil | BSON文档处理工具类 | toDocument(), toJson(), merge() |
| DateUtil | 日期处理工具类 | format(), parse(), addDays() |
| StringUtil | 字符串处理工具类 | isEmpty(), isNotEmpty(), substring() |
| CollectionUtil | 集合处理工具类 | isEmpty(), isNotEmpty(), merge() |
| ReflectUtil | 反射工具类 | getField(), getMethod(), invoke() |
| SecurityUtil | 安全工具类 | encrypt(), decrypt(), md5() |
希望本文对你理解和使用Mongo-Plus有所帮助!如果觉得本文有价值,请点赞、收藏、关注三连支持!如有任何问题或建议,欢迎在评论区留言讨论。
下一期预告:《Mongo-Plus高级特性实战:分布式事务与数据一致性保障》
【免费下载链接】mongo-plus 🔥🔥🔥使用MyBatisPlus的方式,优雅的操作MongoDB 项目地址: https://gitcode.com/aizuda/mongo-plus
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考



