09. Spring Data MongoDB 实战

Spring Data MongoDB: Repository、MongoTemplate、聚合查询、事务与监听的完整实践

Spring Data MongoDB 是 Spring 生态中对 MongoDB 的官方支持,提供了 Repository 接口和 MongoTemplate 两种操作模式。本文覆盖配置、基础 CRUD、复杂查询、聚合与事务。

1. 配置

# application.yml
spring:
  data:
    mongodb:
      uri: mongodb://user:pass@mongo1:27017,mongo2:27017/mydatabase?replicaSet=rs0
      # 或:
      # host: localhost
      # port: 27017
      # database: mydatabase
      # username: user
      # password: pass
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>

2. 实体映射

@Document(collection = "products")
@CompoundIndex(name = "category_price", def = "{'category': 1, 'price': -1}")
public class Product {
    @Id
    private String id;  // 映射 _id

    private String name;
    private String category;
    private BigDecimal price;
    private int stock;

    @Field("created_at")
    private Instant createdAt;

    @DBRef
    private Supplier supplier;  // 引用(慎用,性能差)

    // 嵌套文档
    private List<Review> reviews;
}

public record Review(String userId, int rating, String comment, Instant date) {}

3. Repository 接口

public interface ProductRepository extends MongoRepository<Product, String> {

    // 自动派生查询
    List<Product> findByCategoryAndPriceLessThan(String category, BigDecimal price);

    // 模糊搜索(正则)
    List<Product> findByNameContainingIgnoreCase(String name);

    // 排序分页
    Page<Product> findByCategoryOrderByPriceDesc(String category, Pageable pageable);

    // @Query 自定义
    @Query("{ 'category': ?0, 'price': { $gte: ?1, $lte: ?2 } }")
    List<Product> findByPriceRange(String category, BigDecimal min, BigDecimal max);

    // 聚合统计
    @Aggregation(pipeline = {
        "{ $match: { category: ?0 } }",
        "{ $group: { _id: null, avgPrice: { $avg: '$price' }, totalStock: { $sum: '$stock' } } }"
    })
    ProductStats getStatsByCategory(String category);
}

4. MongoTemplate

@Service
public class ProductService {
    @Autowired private MongoTemplate mongoTemplate;

    public List<Product> search(String keyword, String category) {
        Query query = new Query();

        // 动态条件
        if (StringUtils.hasText(keyword)) {
            query.addCriteria(Criteria.where("name")
                .regex(keyword, "i"));
        }
        if (StringUtils.hasText(category)) {
            query.addCriteria(Criteria.where("category").is(category));
        }

        query.with(Sort.by(Sort.Direction.DESC, "createdAt"));
        query.limit(20);

        return mongoTemplate.find(query, Product.class);
    }

    // 批量更新
    public void updateStockBatch(Map<String, Integer> stockChanges) {
        BulkOperations bulkOps = mongoTemplate.bulkOps(
            BulkOperations.BulkMode.UNORDERED, Product.class);

        stockChanges.forEach((id, qty) -> {
            Query query = Query.query(Criteria.where("_id").is(id));
            Update update = new Update().inc("stock", qty);
            bulkOps.updateOne(query, update);
        });

        bulkOps.execute();
    }

    // 聚合管道
    public List<Document> getCategoryRevenue() {
        Aggregation agg = Aggregation.newAggregation(
            Aggregation.match(Criteria.where("status").is("completed")),
            Aggregation.unwind("items"),
            Aggregation.group("items.category")
                .sum(ArithmeticOperators.Multiply.valueOf("items.price")
                    .multiplyBy("items.quantity")).as("revenue"),
            Aggregation.sort(Sort.Direction.DESC, "revenue")
        );

        return mongoTemplate.aggregate(agg, "orders", Document.class)
            .getMappedResults();
    }
}

5. 事务

@Service
public class OrderService {
    @Autowired private MongoTemplate mongoTemplate;
    @Autowired private MongoTransactionManager transactionManager;

    @Transactional
    public void createOrder(OrderRequest request) {
        // 扣减库存
        mongoTemplate.updateFirst(
            Query.query(Criteria.where("sku").is(request.sku())),
            new Update().inc("stock", -request.qty()),
            Product.class
        );

        // 创建订单
        Order order = new Order(request);
        mongoTemplate.save(order);
    }
}

延伸阅读

继续阅读

探索更多技术文章

浏览归档,发现更多关于系统设计、工具链和工程实践的内容。

全部文章 返回首页

「mongodb」更多文章

  1. 11. MongoDB 安全认证与备份恢复
  2. 10. MongoDB 性能调优与运维监控
  3. 08. MongoDB Change Streams 实时同步