Spring Boot MongoDB 使用技巧

Spring Boot MongoDB 使用技巧

1. 基础配置

1.1 依赖配置

xml 复制代码
<!-- 在pom.xml中添加 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>

1.2 连接配置

yaml 复制代码
# application.yml 配置示例
spring:
  data:
    mongodb:
      uri: mongodb://username:password@host:port/database?authSource=admin
      # 或者使用分开的配置
      # host: localhost
      # port: 27017
      # database: testdb
      # username: admin
      # password: password
      # authentication-database: admin

1.3 多数据源配置

java 复制代码
@Configuration
public class MultipleMongoConfig {

    @Bean(name = "mongoTemplate1")
    @Primary
    public MongoTemplate mongoTemplate1(MongoDatabaseFactory factory1) {
        return new MongoTemplate(factory1);
    }

    @Bean(name = "mongoTemplate2")
    public MongoTemplate mongoTemplate2(@Qualifier("mongoDbFactory2") MongoDatabaseFactory factory2) {
        return new MongoTemplate(factory2);
    }

    // 配置多个MongoDatabaseFactory
}

2. 实体映射技巧

2.1 基础映射注解

java 复制代码
@Document(collection = "users")  // 指定集合名
public class User {
    @Id  // 主键
    private String id;
    
    @Field("user_name")  // 自定义字段名
    private String username;
    
    @Indexed(unique = true)  // 索引配置
    private String email;
    
    @Transient  // 不持久化到数据库
    private String tempField;
    
    // getters and setters
}

2.2 复杂对象映射

java 复制代码
@Document
public class Order {
    @Id
    private String id;
    
    private User user;  // 嵌入文档
    
    private List<OrderItem> items;  // 数组/列表
    
    @DBRef  // 引用其他集合的文档
    private Customer customer;
    
    // getters and setters
}

2.3 时间处理

java 复制代码
@DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME)
private LocalDateTime createdAt;

// 自动填充时间
@PrePersist
public void prePersist() {
    createdAt = LocalDateTime.now();
}

3. 数据访问层设计

3.1 Repository接口方式

java 复制代码
// 基础Repository
public interface UserRepository extends MongoRepository<User, String> {
    // 自动生成查询方法
    Optional<User> findByUsername(String username);
    List<User> findByAgeGreaterThan(int age);
    
    // 自定义查询
    @Query("{ 'email' : ?0, 'status' : ?1 }")
    List<User> findByEmailAndStatus(String email, String status);
}

3.2 MongoTemplate方式

java 复制代码
@Service
public class UserService {
    
    @Autowired
    private MongoTemplate mongoTemplate;
    
    public User findUserByUsername(String username) {
        Query query = new Query(Criteria.where("username").is(username));
        return mongoTemplate.findOne(query, User.class);
    }
    
    public void saveUser(User user) {
        mongoTemplate.save(user);
    }
}

4. 高级查询技巧

4.1 复杂条件查询

java 复制代码
// 使用Criteria构建复杂查询
Criteria criteria = new Criteria();
criteria.and("age").gt(18).lte(60);
criteria.and("status").is("active");
criteria.orOperator(
    Criteria.where("role").is("admin"),
    Criteria.where("permissions").in("WRITE", "DELETE")
);
Query query = Query.query(criteria);
List<User> users = mongoTemplate.find(query, User.class);

4.2 聚合查询

java 复制代码
Aggregation aggregation = Aggregation.newAggregation(
    Aggregation.match(Criteria.where("status").is("active")),
    Aggregation.group("department").count().as("employeeCount"),
    Aggregation.sort(Sort.Direction.DESC, "employeeCount")
);

AggregationResults<DepartmentStats> results = mongoTemplate.aggregate(
    aggregation, "employees", DepartmentStats.class);

4.3 分页查询

java 复制代码
Pageable pageable = PageRequest.of(0, 10, Sort.by("createdAt").descending());
Query query = new Query().with(pageable);
long count = mongoTemplate.count(query, User.class);
List<User> users = mongoTemplate.find(query, User.class);
Page<User> userPage = new PageImpl<>(users, pageable, count);

5. 索引优化

5.1 索引注解配置

java 复制代码
@Document
@CompoundIndex(name = "idx_name_age", def = "{ 'name': 1, 'age': -1 }")
public class User {
    @Indexed(unique = true, sparse = true)  // 唯一索引,稀疏索引
    private String email;
    
    @Indexed(expireAfterSeconds = 3600)  // TTL索引,1小时后过期
    private Date lastLoginTime;
}

5.2 运行时索引管理

java 复制代码
// 创建索引
mongoTemplate.indexOps(User.class).ensureIndex(
    new Index().on("username", Direction.ASC).unique()
);

// 删除索引
mongoTemplate.indexOps(User.class).dropIndex("idx_name_age");

// 查看所有索引
List<IndexInfo> indexes = mongoTemplate.indexOps(User.class).getIndexInfo();

6. 事务支持

6.1 启用事务

java 复制代码
@Configuration
@EnableMongoRepositories
public class MongoConfig extends AbstractMongoClientConfiguration {
    
    @Bean
    @Override
    public MongoTransactionManager transactionManager(MongoDatabaseFactory dbFactory) {
        return new MongoTransactionManager(dbFactory);
    }
}

6.2 使用事务

java 复制代码
@Service
public class OrderService {
    
    @Autowired
    private OrderRepository orderRepository;
    
    @Autowired
    private InventoryService inventoryService;
    
    @Transactional  // Spring事务注解
    public void createOrder(Order order) {
        // 保存订单
        orderRepository.save(order);
        
        // 更新库存
        inventoryService.reduceInventory(order.getItems());
    }
}

7. 性能优化技巧

7.1 字段投影

java 复制代码
// 只返回需要的字段
Query query = new Query(Criteria.where("status").is("active"));
query.fields().include("username").include("email").exclude("password");
List<User> users = mongoTemplate.find(query, User.class);

7.2 批量操作

java 复制代码
// 批量插入
List<User> users = new ArrayList<>();
// 添加用户...
mongoTemplate.insert(users, User.class);

// 批量更新
BulkOperations operations = mongoTemplate.bulkOps(BulkOperations.BulkMode.UNORDERED, User.class);
for (User user : usersToUpdate) {
    Update update = new Update().set("status", user.getStatus());
    operations.updateOne(Query.query(Criteria.where("_id").is(user.getId())), update);
}
operations.execute();

7.3 缓存查询结果

java 复制代码
@Service
public class CacheUserService {
    
    @Autowired
    private UserRepository userRepository;
    
    @Cacheable(value = "users", key = "#username")
    public User findByUsername(String username) {
        return userRepository.findByUsername(username).orElse(null);
    }
}

8. 错误处理与日志

8.1 异常处理

java 复制代码
@ControllerAdvice
public class MongoExceptionHandler {
    
    @ExceptionHandler(DuplicateKeyException.class)
    public ResponseEntity<ErrorResponse> handleDuplicateKey(DuplicateKeyException ex) {
        ErrorResponse error = new ErrorResponse("Duplicate key error", ex.getMessage());
        return new ResponseEntity<>(error, HttpStatus.CONFLICT);
    }
    
    @ExceptionHandler(MongoException.class)
    public ResponseEntity<ErrorResponse> handleMongoException(MongoException ex) {
        ErrorResponse error = new ErrorResponse("MongoDB error", ex.getMessage());
        return new ResponseEntity<>(error, HttpStatus.INTERNAL_SERVER_ERROR);
    }
}

8.2 慢查询日志配置

yaml 复制代码
logging:
  level:
    org.springframework.data.mongodb.core.MongoTemplate: DEBUG  # 开启MongoTemplate日志

9. 测试技巧

9.1 集成测试

java 复制代码
@SpringBootTest
@DataMongoTest  // 只加载MongoDB相关配置
public class UserRepositoryTest {
    
    @Autowired
    private UserRepository userRepository;
    
    @MockBean  // 模拟其他依赖
    private EmailService emailService;
    
    @Test
    public void testFindByUsername() {
        // 测试代码
    }
}

9.2 使用嵌入式MongoDB

xml 复制代码
<dependency>
    <groupId>de.flapdoodle.embed</groupId>
    <artifactId>de.flapdoodle.embed.mongo</artifactId>
    <scope>test</scope>
</dependency>

10. 最佳实践总结

  1. 合理设计文档结构:优先使用嵌入文档,避免过度使用DBRef
  2. 索引策略:为常用查询字段添加索引,但不要过度索引
  3. 事务使用:仅在必要时使用事务,因为会影响性能
  4. 连接池配置:根据应用规模调整连接池参数
  5. 分页查询:避免深度分页,考虑使用游标或时间戳分页
  6. 监控与调优:使用MongoDB Compass等工具监控查询性能
  7. 安全配置:生产环境启用认证、TLS加密
  8. 备份策略:定期备份数据,配置适当的复制集

这些技巧涵盖了Spring Boot与MongoDB集成的各个方面,从基础配置到高级用法和性能优化,希望对你有所帮助!

相关推荐
嫄码4 小时前
BigDecimal对象比较时的注意事项
java
倚栏听风雨4 小时前
RAG检索增强生成(Retrieval Augmented Generation)
后端
我是华为OD~HR~栗栗呀4 小时前
华为OD-23届考研-测试面经
java·c++·python·华为od·华为·面试·单元测试
敲代码的嘎仔4 小时前
JavaWeb零基础学习Day4——Maven
java·开发语言·学习·算法·maven·javaweb·学习方法
倚栏听风雨4 小时前
召回率 精准率 F1 概念解释
后端
残花月伴4 小时前
Consumer 和 Function 接口详解
java
间彧4 小时前
消息队列在流量削峰场景下如何设置合理的队列长度和消费速率?
后端
W.Buffer4 小时前
设计模式-工厂模式:解耦对象创建的设计艺术
java·开发语言·设计模式
程序员爱钓鱼4 小时前
Python编程实战 · 基础入门篇 | 数据类型简介:数字、字符串、布尔值
后端·python