MongoDB初学者教程:从零开始掌握MongoDB(第五阶段:Java集成实践)
欢迎进入MongoDB学习的第五阶段:Java集成实践现在,我们要将这些知识整合到一个真实的Java项目中,使用Spring Boot和Spring Data MongoDB构建一个用户管理系统,展示如何在现代Web开发中高效使用MongoDB。
本阶段将带你:
- 使用Spring Data MongoDB实现Repository模式和自定义查询。
- 启用审计功能(自动记录创建时间等)。
- 实现MongoDB的ACID事务,确保数据一致性。
我们会基于mydb
数据库和users
集合,创建一个Spring Boot应用,提供用户管理的REST API。本阶段约5000字,包含详细代码示例和生活化比喻,确保零基础的你能轻松上手!
第五阶段:Java集成实践
一、Spring Data MongoDB
Spring Data MongoDB是Spring框架的模块,简化了MongoDB的开发。它提供了Repository模式,让你用简单的接口定义就能实现CRUD操作,还支持自定义查询和审计功能。想象Spring Data MongoDB像一个“智能助手”,帮你把MongoDB的复杂操作变成几行代码。
我们将创建一个Spring Boot项目,实现用户管理的增删改查功能。
1. 项目初始化
步骤1:创建Spring Boot项目
-
配置:
- Project:Maven
- Language:Java
- Spring Boot:3.x(最新稳定版,截至2025年5月)
- Group:
com.example
- Artifact:
user-management
- Dependencies:Spring Web、Spring Data MongoDB
-
下载项目,导入IntelliJ IDEA或Eclipse。
步骤2:配置MongoDB连接
编辑src/main/resources/application.properties
:
spring.data.mongodb.uri=mongodb://localhost:27017/mydb
spring.data.mongodb.database=mydb
步骤3:添加依赖
确保pom.xml
包含以下依赖:
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>
</dependencies>
2. Repository模式实现
Repository模式是Spring Data的核心,通过定义接口,自动生成CRUD操作。我们将创建一个UserRepository
来管理users
集合。
定义User实体:
创建src/main/java/com/example/usermanagement/model/User.java
:
package com.example.usermanagement.model;
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;
import java.util.List;
@Document(collection = "users")
public class User {
@Id
private String id;
private String name;
private int age;
private String city;
private List<String> hobbies;
// 构造函数
public User() {}
public User(String name, int age, String city, List<String> hobbies) {
this.name = name;
this.age = age;
this.city = city;
this.hobbies = hobbies;
}
// Getter和Setter
public String getId() { return id; }
public void setId(String id) { this.id = id; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public int getAge() { return age; }
public void setAge(int age) { this.age = age; }
public String getCity() { return city; }
public void setCity(String city) { this.city = city; }
public List<String> getHobbies() { return hobbies; }
public void setHobbies(List<String> hobbies) { this.hobbies = hobbies; }
}
创建Repository:
创建src/main/java/com/example/usermanagement/repository/UserRepository.java
:
package com.example.usermanagement.repository;
import com.example.usermanagement.model.User;
import org.springframework.data.mongodb.repository.MongoRepository;
public interface UserRepository extends MongoRepository<User, String> {
}
说明:
@Document(collection = "users")
:指定MongoDB集合。@Id
:标记主键字段。MongoRepository<User, String>
:提供CRUD方法,User
是实体类,String
是id
类型。
测试Repository:
创建一个REST控制器,测试CRUD操作。创建src/main/java/com/example/usermanagement/controller/UserController.java
:
package com.example.usermanagement.controller;
import com.example.usermanagement.model.User;
import com.example.usermanagement.repository.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import java.util.Optional;
@RestController
@RequestMapping("/users")
public class UserController {
@Autowired
private UserRepository userRepository;
// 创建用户
@PostMapping
public User createUser(@RequestBody User user) {
return userRepository.save(user);
}
// 查询所有用户
@GetMapping
public List<User> getAllUsers() {
return userRepository.findAll();
}
// 查询单个用户
@GetMapping("/{id}")
public Optional<User> getUserById(@PathVariable String id) {
return userRepository.findById(id);
}
// 更新用户
@PutMapping("/{id}")
public User updateUser(@PathVariable String id, @RequestBody User user) {
user.setId(id);
return userRepository.save(user);
}
// 删除用户
@DeleteMapping("/{id}")
public void deleteUser(@PathVariable String id) {
userRepository.deleteById(id);
}
}
运行项目:
-
确保MongoDB服务运行(
mongod
)。 -
运行Spring Boot应用(
mvn spring-boot:run
或通过IDE)。 -
使用Postman或浏览器测试API:
- POST
http://localhost:8080/users
:创建用户(Body:{"name": "小明", "age": 20, "city": "北京", "hobbies": ["读书"]}
) - GET
http://localhost:8080/users
:查询所有用户 - GET
http://localhost:8080/users/{id}
:查询单个用户 - PUT
http://localhost:8080/users/{id}
:更新用户 - DELETE
http://localhost:8080/users/{id}
:删除用户
- POST
生活化比喻:Repository像一个“智能文件柜”,你只要告诉它要存、取、改、删哪个用户,它就自动帮你搞定。
3. 自定义查询方法
Spring Data MongoDB支持通过方法名定义查询,自动生成MongoDB查询语句。我们将为UserRepository
添加自定义查询方法。
修改UserRepository:
package com.example.usermanagement.repository;
import com.example.usermanagement.model.User;
import org.springframework.data.mongodb.repository.MongoRepository;
import java.util.List;
public interface UserRepository extends MongoRepository<User, String> {
// 查找指定城市的用户
List<User> findByCity(String city);
// 查找年龄大于某个值的用户
List<User> findByAgeGreaterThan(int age);
// 查找指定城市且年龄大于某个值的用户
List<User> findByCityAndAgeGreaterThan(String city, int age);
// 查找hobbies包含某项的用户
List<User> findByHobbiesContaining(String hobby);
}
添加控制器方法:
在UserController
中添加:
// 按城市查询
@GetMapping("/city/{city}")
public List<User> getUsersByCity(@PathVariable String city) {
return userRepository.findByCity(city);
}
// 按年龄查询
@GetMapping("/age/{age}")
public List<User> getUsersByAgeGreaterThan(@PathVariable int age) {
return userRepository.findByAgeGreaterThan(age);
}
// 按城市和年龄查询
@GetMapping("/city/{city}/age/{age}")
public List<User> getUsersByCityAndAge(@PathVariable String city, @PathVariable int age) {
return userRepository.findByCityAndAgeGreaterThan(city, age);
}
// 按兴趣查询
@GetMapping("/hobby/{hobby}")
public List<User> getUsersByHobby(@PathVariable String hobby) {
return userRepository.findByHobbiesContaining(hobby);
}
测试自定义查询:
- GET
http://localhost:8080/users/city/北京
:查找北京的用户 - GET
http://localhost:8080/users/age/20
:查找年龄大于20的用户 - GET
http://localhost:8080/users/city/上海/age/20
:查找上海且年龄大于20的用户 - GET
http://localhost:8080/users/hobby/读书
:查找兴趣包含“读书”的用户
说明:
- 方法名如
findByCity
会映射为{"city": ?}
查询。 findByCityAndAgeGreaterThan
映射为{"city": ?, "age": {"$gt": ?}}
。findByHobbiesContaining
映射为数组查询。
生活化比喻:自定义查询方法像告诉“智能文件柜”:“帮我找北京的用户”或“找喜欢读书的人”,它自动翻译成MongoDB查询。
4. 审计功能(@CreatedDate等)
审计功能让MongoDB自动记录文档的创建时间、更新时间等信息,适合跟踪数据变更。我们将为User
添加创建时间和更新时间。
启用审计:
在主应用类上添加@EnableMongoAuditing
:
package com.example.usermanagement;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.data.mongodb.config.EnableMongoAuditing;
@SpringBootApplication
@EnableMongoAuditing
public class UserManagementApplication {
public static void main(String[] args) {
SpringApplication.run(UserManagementApplication.class, args);
}
}
修改User实体:
添加审计字段:
package com.example.usermanagement.model;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.LastModifiedDate;
import org.springframework.data.mongodb.core.mapping.Document;
import java.time.LocalDateTime;
import java.util.List;
@Document(collection = "users")
public class User {
@Id
private String id;
private String name;
private int age;
private String city;
private List<String> hobbies;
@CreatedDate
private LocalDateTime createdDate;
@LastModifiedDate
private LocalDateTime lastModifiedDate;
// 构造函数
public User() {}
public User(String name, int age, String city, List<String> hobbies) {
this.name = name;
this.age = age;
this.city = city;
this.hobbies = hobbies;
}
// Getter和Setter
public String getId() { return id; }
public void setId(String id) { this.id = id; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public int getAge() { return age; }
public void setAge(int age) { this.age = age; }
public String getCity() { return city; }
public void setCity(String city) { this.city = city; }
public List<String> getHobbies() { return hobbies; }
public void setHobbies(List<String> hobbies) { this.hobbies = hobbies; }
public LocalDateTime getCreatedDate() { return createdDate; }
public void setCreatedDate(LocalDateTime createdDate) { this.createdDate = createdDate; }
public LocalDateTime getLastModifiedDate() { return lastModifiedDate; }
public void setLastModifiedDate(LocalDateTime lastModifiedDate) { this.lastModifiedDate = lastModifiedDate; }
}
测试审计:
- POST
http://localhost:8080/users
创建用户,MongoDB会自动设置createdDate
。 - PUT
http://localhost:8080/users/{id}
更新用户,lastModifiedDate
会更新。 - GET
http://localhost:8080/users/{id}
查看用户,确认时间字段。
生活化比喻:审计功能像在便签上自动盖上“创建时间”和“最后修改时间”戳,帮你记录文件历史。
二、事务管理
MongoDB 4.0+支持ACID事务,确保多文档操作的原子性、一致性、隔离性和持久性。Spring Data MongoDB通过@Transactional
简化事务管理。我们将实现一个事务示例,确保用户和相关日志同时保存。
1. ACID事务实现
ACID事务保证多个操作要么全部成功,要么全部回滚。MongoDB的事务需要运行在副本集(Replica Set)或分片集群上。以下是为开发环境配置副本集的简单步骤:
配置副本集(单节点测试):
-
停止当前MongoDB服务。
-
创建数据目录(比如
C:\data\db1
或/data/db1
)。 -
启动MongoDB:
mongod --port 27017 --dbpath /data/db1 --replSet rs0
-
连接MongoDB(
mongosh
),初始化副本集:rs.initiate()
-
确认副本集状态:
rs.status()
修改Spring Boot配置:
更新application.properties
,连接副本集:
spring.data.mongodb.uri=mongodb://localhost:27017/mydb?replicaSet=rs0
2. 多文档事务Java示例
我们将创建一个服务,保存用户并记录操作日志,确保两者在事务中一致。
创建日志实体:
创建src/main/java/com/example/usermanagement/model/LogEntry.java
:
package com.example.usermanagement.model;
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;
import java.time.LocalDateTime;
@Document(collection = "logs")
public class LogEntry {
@Id
private String id;
private String operation;
private String userId;
private LocalDateTime timestamp;
public LogEntry() {}
public LogEntry(String operation, String userId, LocalDateTime timestamp) {
this.operation = operation;
this.userId = userId;
this.timestamp = timestamp;
}
// Getter和Setter
public String getId() { return id; }
public void setId(String id) { this.id = id; }
public String getOperation() { return operation; }
public void setOperation(String operation) { this.operation = operation; }
public String getUserId() { return userId; }
public void setUserId(String userId) { this.userId = userId; }
public LocalDateTime getTimestamp() { return timestamp; }
public void setTimestamp(LocalDateTime timestamp) { this.timestamp = timestamp; }
}
创建日志Repository:
创建src/main/java/com/example/usermanagement/repository/LogRepository.java
:
package com.example.usermanagement.repository;
import com.example.usermanagement.model.LogEntry;
import org.springframework.data.mongodb.repository.MongoRepository;
public interface LogRepository extends MongoRepository<LogEntry, String> {
}
创建服务层:
创建src/main/java/com/example/usermanagement/service/UserService.java
:
package com.example.usermanagement.service;
import com.example.usermanagement.model.LogEntry;
import com.example.usermanagement.model.User;
import com.example.usermanagement.repository.LogRepository;
import com.example.usermanagement.repository.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.time.LocalDateTime;
@Service
public class UserService {
@Autowired
private UserRepository userRepository;
@Autowired
private LogRepository logRepository;
@Transactional
public User createUserWithLog(User user) {
// 保存用户
User savedUser = userRepository.save(user);
// 保存日志
LogEntry log = new LogEntry("CREATE_USER", savedUser.getId(), LocalDateTime.now());
logRepository.save(log);
// 模拟错误,测试事务回滚
if (user.getName().equals("error")) {
throw new RuntimeException("Simulated error");
}
return savedUser;
}
}
修改控制器:
在UserController
中调用服务:
@Autowired
private UserService userService;
@PostMapping("/with-log")
public User createUserWithLog(@RequestBody User user) {
return userService.createUserWithLog(user);
}
测试事务:
-
POST
http://localhost:8080/users/with-log
:- Body:
{"name": "小明", "age": 20, "city": "北京", "hobbies": ["读书"]}
- 成功:用户和日志都保存。
- Body:
-
POST
http://localhost:8080/users/with-log
:- Body:
{"name": "error", "age": 20, "city": "北京", "hobbies": ["读书"]}
- 失败:事务回滚,用户和日志都不保存。
- Body:
说明:
@Transactional
确保用户和日志操作在同一事务中。- 如果抛出异常(如
RuntimeException
),MongoDB回滚所有操作。
生活化比喻:事务像一次“原子操作”,要么把用户便签和日志便签都放进文件夹,要么一张都不放,保证文件夹始终整齐。
总结与回顾
恭喜你完成了MongoDB的全部五阶段学习!通过本阶段,你:
- 学会了用Spring Data MongoDB实现Repository模式和自定义查询。
- 启用了审计功能,自动记录时间戳。
- 实现了MongoDB的ACID事务,确保数据一致性。
- 构建了一个简单的用户管理系统,整合了前四阶段的CRUD、查询、索引等知识。
你的MongoDB“文件夹”现在不仅灵活,还高效、可靠!以下是整个教程的回顾:
- 第一阶段:了解MongoDB基础、NoSQL、BSON,搭建环境。
- 第二阶段:掌握CRUD操作,用Java驱动实现增删改查。
- 第三阶段:学习复杂查询(条件、逻辑、数组)和聚合框架。
- 第四阶段:优化性能,创建索引,分析执行计划。
- 第五阶段:整合Spring Boot,开发用户管理系统。
接下来做什么?
- 扩展项目:为用户管理系统添加更多功能,如分页查询、用户认证。
- 深入学习:探索MongoDB的分布式部署、分片、备份恢复。
- 实战应用:将MongoDB应用到自己的项目中,比如博客、电商平台。
你已经从MongoDB新手成长为有实战能力的开发者!继续探索,未来可期!