SpringBoot整合MongoDB详解:从基础到高级实践

MongoDB与SpringBoot概述

什么是MongoDB?

MongoDB是一个基于分布式文件存储的NoSQL数据库,采用文档型数据模型(BSON格式,类似JSON)。与传统关系型数据库相比:

特性MongoDB传统关系型数据库
数据模型文档型表结构
扩展方式水平扩展(分片)垂直扩展
查询语言MQLSQL
事务支持4.0+版本支持多文档完全支持
适用场景大数据量、高并发、灵活模式强一致性、复杂关系

为什么选择SpringBoot整合MongoDB?

  • 简化配置:Spring Data MongoDB提供自动配置
  • 丰富的模板:MongoTemplate和Repository支持
  • 对象映射:通过注解实现POJO与文档映射
  • 事务支持:简化分布式事务管理
  • 生态整合:与Spring其他组件无缝协作

环境准备与基础配置

1. 依赖引入

<dependencies>
    <!-- Spring Boot Starter for MongoDB -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-mongodb</artifactId>
    </dependency>
    
    <!-- 如果需要验证等功能 -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-validation</artifactId>
    </dependency>
    
    <!-- Lombok简化代码 -->
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <optional>true</optional>
    </dependency>
</dependencies>

2. 基础配置详解

application.yml 配置示例:

spring:
  data:
    mongodb:
      # 单机模式配置
      host: localhost
      port: 27017
      database: blog_db
      username: blog_user  # 可选
      password: securepwd  # 可选
      
      # 连接池配置
      authentication-database: admin  # 认证数据库
      auto-index-creation: true      # 自动创建索引
      
      # 副本集配置示例
      # uri: mongodb://user:pass@host1:port1,host2:port2/database?replicaSet=rs0
      
      # 连接池配置
      connection-pool:
        max-size: 100                # 最大连接数
        min-size: 10                 # 最小连接数
        max-wait-time: 30000         # 最大等待时间(ms)

配置项解析表:

配置项说明默认值建议值
hostMongoDB服务器地址localhost根据环境配置
portMongoDB端口27017-
database默认数据库-必填
auto-index-creation是否自动创建索引false开发环境true,生产环境false
max-size连接池最大连接数100根据并发量调整
min-size连接池最小连接数010-20
max-wait-time获取连接最大等待时间(ms)12000030000-60000

3. 实体类映射

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.util.Date;
import java.util.List;

@Document(collection = "users")  // 指定集合名称
@Data  // Lombok注解,自动生成getter/setter等
@NoArgsConstructor
@AllArgsConstructor
public class User {
    
    @Id  // 主键标识
    private String id;
    
    @Indexed(unique = true)  // 唯一索引
    private String username;
    
    @Field("pwd")  // 指定文档中字段名
    private String password;
    
    private Integer age;
    
    @Indexed  // 普通索引
    private Date createTime;
    
    private List<String> hobbies;  // 数组类型
    
    private Address address;  // 嵌套文档
}

@Data
@NoArgsConstructor
@AllArgsConstructor
public class Address {
    private String city;
    private String street;
    private String zipCode;
}

注解说明表:

注解作用示例
@Document标识该类对应MongoDB文档@Document(collection=“users”)
@Id标识主键字段@Id private String id;
@Field指定文档字段名@Field(“pwd”) private String password;
@Indexed创建索引@Indexed(unique=true)
@Transient不持久化到数据库@Transient private String temp;
@DBRef引用其他文档@DBRef private Department dept;

核心CRUD操作

1. MongoTemplate基础操作

@SpringBootTest
public class MongoTemplateTest {

    @Autowired
    private MongoTemplate mongoTemplate;
    
    // 插入文档
    @Test
    public void testInsert() {
        User user = new User(null, "user1", "123456", 25, new Date(), 
                           Arrays.asList("reading", "swimming"),
                           new Address("Beijing", "Main St", "100001"));
        
        // insert方法: 插入单个文档
        User insertedUser = mongoTemplate.insert(user);  // 返回插入后的对象(包含生成的id)
        System.out.println("Inserted user id: " + insertedUser.getId());
        
        // insertAll方法: 批量插入
        List<User> users = Arrays.asList(
            new User(null, "user2", "111111", 30, new Date(), Arrays.asList("hiking"), 
                    new Address("Shanghai", "Nanjing Rd", "200001")),
            new User(null, "user3", "222222", 28, new Date(), Arrays.asList("music"), 
                    new Address("Guangzhou", "Zhongshan Rd", "510000"))
        );
        Collection<User> insertedUsers = mongoTemplate.insertAll(users);
        insertedUsers.forEach(u -> System.out.println("Inserted: " + u.getUsername()));
    }
    
    // 查询文档
    @Test
    public void testQuery() {
        // 1. 根据ID查询
        User user = mongoTemplate.findById("5f8d8a7c6b3a1d2e3c4b5a6", User.class);
        System.out.println("Find by ID: " + user);
        
        // 2. 查询所有
        List<User> allUsers = mongoTemplate.findAll(User.class);
        allUsers.forEach(u -> System.out.println("All users: " + u.getUsername()));
        
        // 3. 条件查询
        Query query = new Query(Criteria.where("age").gt(25).lt(30)
                                  .and("hobbies").in("reading"));
        List<User> users = mongoTemplate.find(query, User.class);
        users.forEach(u -> System.out.println("Conditional query: " + u.getUsername()));
    }
    
    // 更新文档
    @Test
    public void testUpdate() {
        // 1. 更新第一个匹配的文档
        Query query = new Query(Criteria.where("username").is("user1"));
        Update update = new Update().set("age", 26).inc("loginCount", 1);
        UpdateResult result = mongoTemplate.updateFirst(query, update, User.class);
        System.out.println("Matched: " + result.getMatchedCount() + 
                         ", Modified: " + result.getModifiedCount());
        
        // 2. 更新所有匹配的文档
        Update multiUpdate = new Update().set("active", true);
        UpdateResult multiResult = mongoTemplate.updateMulti(
            new Query(Criteria.where("age").gt(25)), 
            multiUpdate, 
            User.class
        );
        
        // 3. upsert操作(不存在则插入)
        Update upsertUpdate = new Update().setOnInsert("username", "newUser")
                                         .set("age", 20);
        UpdateResult upsertResult = mongoTemplate.upsert(
            new Query(Criteria.where("username").is("newUser")),
            upsertUpdate,
            User.class
        );
        System.out.println("Upserted ID: " + upsertResult.getUpsertedId());
    }
    
    // 删除文档
    @Test
    public void testDelete() {
        // 1. 根据ID删除
        User user = mongoTemplate.findById("5f8d8a7c6b3a1d2e3c4b5a6", User.class);
        if (user != null) {
            DeleteResult result = mongoTemplate.remove(user);
            System.out.println("Deleted count: " + result.getDeletedCount());
        }
        
        // 2. 条件删除
        Query query = new Query(Criteria.where("age").lt(20));
        DeleteResult multiResult = mongoTemplate.remove(query, User.class);
        System.out.println("Deleted count: " + multiResult.getDeletedCount());
    }
}

2. Repository方式操作

定义Repository接口:

public interface UserRepository extends MongoRepository<User, String> {
    
    // 方法名派生查询
    List<User> findByAgeBetween(int min, int max);
    
    List<User> findByHobbiesIn(List<String> hobbies);
    
    // 使用@Query注解
    @Query("{ 'age' : { $gt: ?0, $lt: ?1 } }")
    List<User> findUsersByAgeRange(int minAge, int maxAge);
    
    // 分页查询
    Page<User> findByAddressCity(String city, Pageable pageable);
    
    // 排序查询
    List<User> findByUsernameLike(String username, Sort sort);
}

Repository使用示例:

@SpringBootTest
public class RepositoryTest {

    @Autowired
    private UserRepository userRepository;
    
    @Test
    public void testCRUD() {
        // 保存(插入或更新)
        User newUser = new User(null, "repoUser", "password", 30, new Date(), 
                              Arrays.asList("coding"), 
                              new Address("Shenzhen", "Tech Ave", "518000"));
        userRepository.save(newUser);
        
        // 查询
        Optional<User> found = userRepository.findById(newUser.getId());
        found.ifPresent(user -> System.out.println("Found: " + user.getUsername()));
        
        // 派生方法查询
        List<User> ageBetween = userRepository.findByAgeBetween(25, 35);
        ageBetween.forEach(u -> System.out.println("Age between: " + u.getUsername()));
        
        // 分页查询
        Page<User> page = userRepository.findByAddressCity(
            "Beijing", 
            PageRequest.of(0, 2, Sort.by("age").descending())
        );
        System.out.println("Total pages: " + page.getTotalPages());
        page.getContent().forEach(u -> System.out.println("Page user: " + u.getUsername()));
        
        // 删除
        userRepository.deleteById(newUser.getId());
    }
}

查询方法与高级查询

1. 查询构建方式对比

查询方式优点缺点适用场景
MongoTemplate灵活,支持所有MongoDB操作代码量较大复杂查询、聚合操作
方法名派生简单,无需实现功能有限,方法名可能过长简单条件查询
@Query注解平衡灵活性和简洁性需要学习MongoDB JSON语法中等复杂度查询

2. 复杂查询示例

public class AdvancedQueryTest {

    @Autowired
    private MongoTemplate mongoTemplate;
    
    // 1. 多条件组合查询
    @Test
    public void testMultiCriteria() {
        Criteria criteria = new Criteria();
        criteria.andOperator(
            Criteria.where("age").gt(20),
            Criteria.where("address.city").is("Beijing"),
            Criteria.where("hobbies").size(2)
        );
        
        Query query = new Query(criteria)
            .with(Sort.by(Sort.Direction.DESC, "createTime"))
            .skip(0)
            .limit(5);
            
        List<User> users = mongoTemplate.find(query, User.class);
        users.forEach(u -> System.out.println("Complex query result: " + u));
    }
    
    // 2. 正则表达式查询
    @Test
    public void testRegex() {
        // 查询用户名包含"john"不区分大小写的用户
        Pattern pattern = Pattern.compile("john", Pattern.CASE_INSENSITIVE);
        Query query = new Query(Criteria.where("username").regex(pattern));
        List<User> users = mongoTemplate.find(query, User.class);
    }
    
    // 3. 数组查询
    @Test
    public void testArrayQuery() {
        // 查询hobbies包含"reading"和"swimming"的用户
        Query query1 = new Query(Criteria.where("hobbies").all("reading", "swimming"));
        
        // 查询hobbies数组第二个元素为"music"的用户
        Query query2 = new Query(Criteria.where("hobbies.1").is("music"));
        
        // 查询hobbies数组长度大于3的用户
        Query query3 = new Query(Criteria.where("hobbies").size(3));
    }
    
    // 4. 投影查询(只返回指定字段)
    @Test
    public void testProjection() {
        Query query = new Query(Criteria.where("age").gt(25));
        query.fields()
            .include("username", "age")  // 包含字段
            .exclude("password")        // 排除字段
            .elemMatch("hobbies");      // 数组元素匹配
            
        List<User> users = mongoTemplate.find(query, User.class);
    }
}

3. 地理空间查询

首先在实体类中添加地理空间信息:

@Document(collection = "places")
@Data
public class Place {
    @Id
    private String id;
    private String name;
    
    @GeoSpatialIndexed(type = GeoSpatialIndexType.GEO_2DSPHERE)
    private GeoJsonPoint location;
}

地理空间查询示例:

public class GeoQueryTest {

    @Autowired
    private MongoTemplate mongoTemplate;
    
    @Test
    public void testNearQuery() {
        // 1. 准备测试数据
        Place p1 = new Place(null, "Central Park", new GeoJsonPoint(-73.968285, 40.785091));
        Place p2 = new Place(null, "Empire State", new GeoJsonPoint(-73.9857, 40.7484));
        mongoTemplate.insertAll(Arrays.asList(p1, p2));
        
        // 2. 附近查询(距离某点1000米内的地点)
        Point point = new Point(-73.9667, 40.78);
        Distance distance = new Distance(1, Metrics.KILOMETERS);
        
        Query query = new Query(
            Criteria.where("location").nearSphere(point).maxDistance(distance.getNormalizedValue())
        );
        
        List<Place> places = mongoTemplate.find(query, Place.class);
        places.forEach(p -> System.out.println("Nearby place: " + p.getName()));
    }
    
    @Test
    public void testGeoWithin() {
        // 查询位于多边形区域内的地点
        List<Point> polygonPoints = Arrays.asList(
            new Point(-73.992787, 40.758896),
            new Point(-73.961304, 40.760148),
            new Point(-73.950676, 40.728669),
            new Point(-73.984513, 40.728928),
            new Point(-73.992787, 40.758896)  // 闭合多边形
        );
        
        Query query = new Query(
            Criteria.where("location").within(new GeoJsonPolygon(polygonPoints))
        );
        
        List<Place> places = mongoTemplate.find(query, Place.class);
    }
}

聚合框架

MongoDB聚合框架提供了强大的数据处理能力,类似于SQL中的GROUP BY、JOIN等操作。

1. 基本聚合操作

public class AggregationTest {

    @Autowired
    private MongoTemplate mongoTemplate;
    
    // 1. 统计各城市用户数量
    @Test
    public void testGroupBy() {
        Aggregation aggregation = Aggregation.newAggregation(
            Aggregation.group("address.city").count().as("userCount"),
            Aggregation.sort(Sort.Direction.DESC, "userCount"),
            Aggregation.limit(10)
        );
        
        AggregationResults<Document> results = mongoTemplate.aggregate(
            aggregation, "users", Document.class);
            
        results.getMappedResults().forEach(doc -> {
            System.out.println(doc.getString("_id") + ": " + doc.getInteger("userCount"));
        });
    }
    
    // 2. 多阶段聚合:筛选->分组->排序
    @Test
    public void testMultiStageAggregation() {
        Aggregation aggregation = Aggregation.newAggregation(
            Aggregation.match(Criteria.where("age").gt(20)),  // 阶段1: 筛选
            Aggregation.group("address.city")  // 阶段2: 按城市分组
                .avg("age").as("avgAge")
                .sum("age").as("totalAge")
                .count().as("userCount"),
            Aggregation.sort(Sort.Direction.DESC, "userCount"),  // 阶段3: 排序
            Aggregation.project()  // 阶段4: 投影
                .and("_id").as("city")
                .and("avgAge").as("averageAge")
                .and("totalAge").as("totalAge")
                .and("userCount").as("count")
                .andExclude("_id")
        );
        
        AggregationResults<Document> results = mongoTemplate.aggregate(
            aggregation, "users", Document.class);
    }
}

2. 聚合操作符详解

常用聚合阶段:

阶段说明等效SQL
$match筛选文档WHERE
$group分组GROUP BY
$sort排序ORDER BY
$project投影(选择字段)SELECT
$limit限制结果数量LIMIT
$skip跳过文档OFFSET
$unwind展开数组-
$lookup关联查询LEFT OUTER JOIN

常用聚合表达式:

表达式说明示例
$sum求和$sum: 1 (计数)
$avg平均值 a v g : " avg: " avg:"age"
$min最小值 m i n : " min: " min:"price"
$max最大值 m a x : " max: " max:"score"
$push将值加入数组 p u s h : " push: " push:"name"
$addToSet将唯一值加入数组 a d d T o S e t : " addToSet: " addToSet:"category"
$first获取第一个文档值 f i r s t : " first: " first:"timestamp"
$last获取最后一个文档值 l a s t : " last: " last:"status"

3. 关联查询($lookup)

// 用户和订单关联查询
@Test
public void testLookup() {
    Aggregation aggregation = Aggregation.newAggregation(
        Aggregation.lookup("orders", "id", "userId", "userOrders"),
        Aggregation.match(Criteria.where("userOrders").not().size(0)),
        Aggregation.project()
            .and("username").as("name")
            .and("userOrders").as("orders")
            .andExclude("_id")
    );
    
    AggregationResults<Document> results = mongoTemplate.aggregate(
        aggregation, "users", Document.class);
        
    results.getMappedResults().forEach(doc -> {
        System.out.println(doc.getString("name") + " has " + 
                         doc.getList("orders", Document.class).size() + " orders");
    });
}

事务管理

MongoDB 4.0+ 支持多文档ACID事务。

1. 配置事务支持

@Configuration
public class MongoConfig {

    @Bean
    public MongoTransactionManager transactionManager(MongoDatabaseFactory dbFactory) {
        return new MongoTransactionManager(dbFactory);
    }
}

2. 编程式事务

@Service
public class UserService {

    @Autowired
    private MongoTemplate mongoTemplate;
    @Autowired
    private MongoTransactionManager transactionManager;
    
    public void transferPoints(String fromUserId, String toUserId, int points) {
        // 获取事务定义
        DefaultTransactionDefinition def = new DefaultTransactionDefinition();
        def.setReadOnly(false);
        def.setIsolationLevel(TransactionDefinition.ISOLATION_READ_COMMITTED);
        def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
        
        // 开启事务
        TransactionStatus status = transactionManager.getTransaction(def);
        
        try {
            // 扣减源用户积分
            Query fromQuery = new Query(Criteria.where("id").is(fromUserId));
            Update fromUpdate = new Update().inc("points", -points);
            mongoTemplate.updateFirst(fromQuery, fromUpdate, User.class);
            
            // 增加目标用户积分
            Query toQuery = new Query(Criteria.where("id").is(toUserId));
            Update toUpdate = new Update().inc("points", points);
            mongoTemplate.updateFirst(toQuery, toUpdate, User.class);
            
            // 提交事务
            transactionManager.commit(status);
        } catch (Exception e) {
            // 回滚事务
            transactionManager.rollback(status);
            throw new RuntimeException("Transfer failed", e);
        }
    }
}

3. 声明式事务(@Transactional)

@Service
public class OrderService {

    @Autowired
    private MongoTemplate mongoTemplate;
    
    @Transactional
    public void placeOrder(Order order) {
        // 1. 保存订单
        mongoTemplate.insert(order);
        
        // 2. 更新用户订单计数
        Query query = new Query(Criteria.where("id").is(order.getUserId()));
        Update update = new Update().inc("orderCount", 1);
        mongoTemplate.updateFirst(query, update, User.class);
        
        // 3. 更新库存
        order.getItems().forEach(item -> {
            Query stockQuery = new Query(
                Criteria.where("productId").is(item.getProductId())
            );
            Update stockUpdate = new Update().inc("quantity", -item.getQuantity());
            mongoTemplate.updateFirst(stockQuery, stockUpdate, Inventory.class);
        });
    }
}

事务配置注意事项:

  1. MongoDB事务需要复制集或分片集群
  2. 事务默认超时时间为60秒,可通过@Transactional(timeout=30)调整
  3. 跨多个集合的事务操作需要相同的会话

性能优化

1. 索引优化

// 1. 创建索引
@SpringBootTest
public class IndexTest {

    @Autowired
    private MongoTemplate mongoTemplate;
    
    @Test
    public void createIndexes() {
        // 单字段索引
        mongoTemplate.indexOps(User.class).ensureIndex(
            new Index().on("username", Sort.Direction.ASC).unique()
        );
        
        // 复合索引
        mongoTemplate.indexOps(User.class).ensureIndex(
            new Index().on("age", Sort.Direction.ASC)
                      .on("createTime", Sort.Direction.DESC)
                      .named("age_createTime_idx")
        );
        
        // 文本索引
        mongoTemplate.indexOps(BlogPost.class).ensureIndex(
            new Index().on("title", Sort.Direction.ASC)
                      .on("content", Sort.Direction.ASC)
                      .named("text_idx")
        );
    }
    
    // 2. 查看索引
    @Test
    public void listIndexes() {
        IndexOperations indexOps = mongoTemplate.indexOps(User.class);
        indexOps.getIndexInfo().forEach(index -> {
            System.out.println("Index: " + index.getName());
            System.out.println("Keys: " + index.getIndexKeys());
            System.out.println("Options: " + index.getIndexOptions());
        });
    }
}

索引设计原则:

  1. ESR规则(Equality, Sort, Range)设计复合索引
  2. 查询覆盖率尽量高
  3. 写频繁的集合避免过多索引
  4. 定期监控和优化索引

2. 读写分离

配置副本集读写分离:

spring:
  data:
    mongodb:
      uri: mongodb://user:pass@primary:27017,secondary1:27017,secondary2:27017/db?replicaSet=rs0&readPreference=secondaryPreferred

读偏好(Read Preference)选项:

选项说明适用场景
primary只从主节点读(默认)强一致性要求
primaryPreferred优先主节点,不可用时从从节点读多数情况可用
secondary只从从节点读报表查询等非实时需求
secondaryPreferred优先从节点,不可用时从主节点读读写分离场景
nearest从网络延迟最低的节点读地理分布式应用

3. 批量操作优化

public class BulkOperationsTest {

    @Autowired
    private MongoTemplate mongoTemplate;
    
    @Test
    public void testBulkOps() {
        // 1. 有序批量操作(顺序执行,出错即停止)
        BulkOperations bulkOps = mongoTemplate.bulkOps(BulkMode.ORDERED, User.class);
        
        // 添加多个操作
        for (int i = 0; i < 100; i++) {
            Query query = new Query(Criteria.where("username").is("user" + i));
            Update update = new Update().set("lastLogin", new Date());
            bulkOps.upsert(query, update);
        }
        
        // 执行批量操作
        BulkWriteResult result = bulkOps.execute();
        System.out.println("Inserted: " + result.getInsertedCount());
        System.out.println("Updated: " + result.getModifiedCount());
        
        // 2. 无序批量操作(并行执行,效率更高)
        BulkOperations unorderedBulk = mongoTemplate.bulkOps(BulkMode.UNORDERED, User.class);
        // ...添加操作
    }
}

批量操作建议:

  1. 大批量操作使用UNORDERED模式
  2. 合理设置批量大小(通常100-1000个操作一批)
  3. 考虑在低峰期执行大批量操作

安全配置

1. 认证与授权

MongoDB用户角色:

角色权限
read只读权限
readWrite读写权限
dbAdmin数据库管理权限
userAdmin用户管理权限
clusterAdmin集群管理权限(admin数据库)

创建用户示例:

// 在MongoDB shell中执行
use blog_db
db.createUser({
  user: "blog_user",
  pwd: "securepwd",
  roles: [
    { role: "readWrite", db: "blog_db" },
    { role: "read", db: "reporting" }
  ]
})

2. 加密配置

spring:
  data:
    mongodb:
      uri: mongodb://user:pass@host:27017/db?ssl=true&tlsInsecure=true
      auto-index-creation: false  # 生产环境建议关闭

安全建议:

  1. 启用TLS/SSL加密传输
  2. 使用强密码并定期更换
  3. 遵循最小权限原则分配角色
  4. 启用审计日志(企业版)
  5. 配置网络访问控制

3. 字段级加密

@Document
@Data
public class Patient {
    @Id
    private String id;
    
    private String name;
    
    @Encrypted  // 需要配置加密密钥
    private String ssn;  // 社会安全号
    
    @Field(targetType = FieldType.BINARY)
    private byte[] medicalReport;  // 加密存储的二进制数据
}

最佳实践与常见问题

1. 设计模式建议

嵌入 vs 引用 选择指南:

考虑因素嵌入文档引用文档
数据关系一对一或一对少一对多或多对多
数据大小小文档大文档
变化频率不频繁变化频繁变化
一致性要求强一致性最终一致性
读取模式需要一起读取单独读取

示例场景

  • 用户地址适合嵌入(一对一,变化不频繁)
  • 博客评论可嵌入(一对少,通常一起查询)
  • 订单商品适合引用(可能变化,需要独立管理)

2. 常见问题解决方案

问题1:查询性能慢

  • 检查是否使用了合适的索引(explain()分析)
  • 避免全表扫描和大结果集
  • 考虑分页或游标查询

问题2:写入延迟高

  • 检查写入关注级别(write concern)
  • 考虑批量写入代替单条写入
  • 评估是否需要索引优化

问题3:连接池耗尽

  • 调整连接池大小
  • 确保正确关闭连接
  • 使用连接池监控
// 获取连接池统计信息
@Autowired
private MongoClient mongoClient;

public void printPoolStats() {
    MongoClientSettings settings = mongoClient.getSettings();
    ConnectionPoolSettings poolSettings = settings.getConnectionPoolSettings();
    
    System.out.println("Max connections: " + poolSettings.getMaxSize());
    System.out.println("Min connections: " + poolSettings.getMinSize());
    System.out.println("Wait queue size: " + poolSettings.getMaxWaitQueueSize());
    
    // 更详细的统计需要特定驱动版本支持
}

3. 监控与维护

关键监控指标:

指标说明健康值
查询执行时间查询耗时<100ms
扫描/返回比扫描文档数与返回数比接近1:1
连接数当前活跃连接<75%最大连接数
队列长度等待操作的请求数
内存使用工作集大小小于物理内存

Spring Boot Actuator集成:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

配置application.yml:

management:
  endpoints:
    web:
      exposure:
        include: health,metrics,mongodb
  endpoint:
    health:
      show-details: always

访问/actuator/mongodb获取MongoDB健康状态。

总结

本文全面介绍了Spring Boot与MongoDB的整合,从基础配置到高级特性,涵盖了:

  1. 基础操作:CRUD、查询构建、Repository模式
  2. 高级特性:聚合框架、事务管理、地理查询
  3. 性能优化:索引设计、批量操作、读写分离
  4. 安全实践:认证授权、加密传输
  5. 运维知识:监控、连接池管理、常见问题

MongoDB与Spring Boot的组合为现代应用开发提供了灵活、可扩展的数据持久化方案。根据应用特点合理选择文档设计模式,充分利用MongoDB的优势,同时注意其与传统关系型数据库的差异,才能构建高性能的应用程序。

附录

常用命令对照表

MongoDB操作SQL等效MongoTemplate方法
db.collection.find()SELECTfind()/query()
db.collection.insert()INSERTinsert()/save()
db.collection.update()UPDATEupdateFirst()/updateMulti()
db.collection.remove()DELETEremove()
db.collection.aggregate()GROUP BYaggregate()
db.collection.createIndex()CREATE INDEXindexOps().ensureIndex()

版本兼容性

Spring Boot版本Spring Data MongoDB版本MongoDB驱动版本MongoDB服务器版本
2.4.x3.1.x4.1.x4.2-4.4
2.5.x3.2.x4.2.x4.2-5.0
2.6.x3.3.x4.4.x4.4-5.0
2.7.x3.4.x4.6.x5.0+
3.0.x4.0.x4.8.x5.0+

收藏与否,我不在乎(才怪)。

喜欢的点个关注,想了解更多的可以关注微信公众号 “Eric的技术杂货库” ,提供更多的干货以及资料下载保存!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Clf丶忆笙

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值