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. 最佳实践总结
- 合理设计文档结构:优先使用嵌入文档,避免过度使用DBRef
- 索引策略:为常用查询字段添加索引,但不要过度索引
- 事务使用:仅在必要时使用事务,因为会影响性能
- 连接池配置:根据应用规模调整连接池参数
- 分页查询:避免深度分页,考虑使用游标或时间戳分页
- 监控与调优:使用MongoDB Compass等工具监控查询性能
- 安全配置:生产环境启用认证、TLS加密
- 备份策略:定期备份数据,配置适当的复制集
这些技巧涵盖了Spring Boot与MongoDB集成的各个方面,从基础配置到高级用法和性能优化,希望对你有所帮助!