- 环境准备:安装 MongoDB 和 Java 开发环境。
- 项目创建:使用 Maven 创建项目。
- 核心依赖:介绍并添加 MongoDB Java 驱动。
- 连接数据库:建立与 MongoDB 服务器的连接。
- CRUD 操作:创建、读取、更新、删除文档。
- 高级查询:条件查询、排序、分页。
- 索引:创建和使用索引以提高查询性能。
- 聚合框架:进行复杂的数据分析。
- 完整项目示例:一个包含所有上述功能的可运行示例。
- 最佳实践:连接池、异常处理、文档映射等。
环境准备
在开始之前,请确保你已经安装了以下软件:

- Java Development Kit (JDK): 版本 8 或更高版本。
- Apache Maven: 用于项目构建和依赖管理。
- MongoDB Server: 可以是本地安装的,也可以是 MongoDB Atlas (云服务)。
验证安装: 打开终端或命令提示符,运行以下命令:
java -version mvn -version mongod --version # 如果是本地安装
项目创建 (使用 Maven)
我们将使用 Maven 来创建一个标准的 Java 项目。
-
创建项目目录:
mkdir mongodb-java-project cd mongodb-java-project
-
创建 Maven 项目结构:
(图片来源网络,侵删)mkdir -p src/main/java/com/example/mongodb mkdir -p src/main/resources mkdir -p src/test/java/com/example/mongodb
-
创建
pom.xml文件: 在项目根目录下创建pom.xml文件,这是 Maven 项目的核心配置文件。<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.example</groupId> <artifactId>mongodb-java-project</artifactId> <version>1.0-SNAPSHOT</version> <properties> <maven.compiler.source>11</maven.compiler.source> <maven.compiler.target>11</maven.compiler.target> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <mongodb.driver.version>4.11.1</mongodb.driver.version> </properties> <dependencies> <!-- MongoDB Java Driver --> <dependency> <groupId>org.mongodb</groupId> <artifactId>mongodb-driver-sync</artifactId> <version>${mongodb.driver.version}</version> </dependency> <!-- For JSON-B (optional, for POJO mapping) --> <dependency> <groupId>javax.json</groupId> <artifactId>javax.json-api</artifactId> <version>1.1.4</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.8.1</version> <configuration> <source>11</source> <target>11</target> </configuration> </plugin> </plugins> </build> </project>
核心依赖
我们主要依赖 mongodb-driver-sync,这是 MongoDB 官方提供的同步 Java 驱动,适用于大多数标准 Java 应用程序。
连接数据库
在 Java 代码中,与 MongoDB 交互的第一步是建立连接,核心类是 MongoClient。
MongoClientExample.java
package com.example.mongodb;
import com.mongodb.client.MongoClient;
import com.mongodb.client.MongoClients;
import com.mongodb.client.MongoDatabase;
public class MongoClientExample {
public static void main(String[] args) {
// MongoDB 连接字符串
// 格式: mongodb://[username:password@]host1[:port1][,host2[:port2],...[,hostN[:portN]]][/[database][?options]]
String uri = "mongodb://localhost:27017"; // 连接到本地默认端口
// 创建 MongoClient 实例
// 从 MongoDB 4.0+ 开始,推荐使用 MongoClients.create(),它会自动管理连接池
try (MongoClient mongoClient = MongoClients.create(uri)) {
// 连接到指定的数据库
// 如果数据库不存在,MongoDB 会在第一次插入数据时自动创建
MongoDatabase database = mongoClient.getDatabase("mydb");
System.out.println("成功连接到数据库: " + database.getName());
// 获取集合 (Collection)
// 集合类似于关系型数据库中的表
// database.getCollection("myCollection"); // 这行代码只是获取集合对象,不会创建
} catch (Exception e) {
System.err.println("连接 MongoDB 失败: " + e.getMessage());
e.printStackTrace();
}
}
}
运行:
在 pom.xml 所在目录运行 mvn compile,然后运行 java -cp "target/classes:$(mvn dependency:build-classpath -Dmdep.outputFile=/dev/stdout)" com.example.mongodb.MongoClientExample。
CRUD 操作
这是最核心的部分,我们将使用 MongoCollection 对象来操作文档。
我们定义一个简单的 Java 对象(POJO)来表示我们的文档:
User.java
package com.example.mongodb;
import org.bson.types.ObjectId;
public class User {
private ObjectId id;
private String name;
private int age;
private String city;
// Getters and Setters
public ObjectId getId() { return id; }
public void setId(ObjectId 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; }
@Override
public String toString() {
return "User{" +
"id=" + id +
", name='" + name + '\'' +
", age=" + age +
", city='" + city + '\'' +
'}';
}
}
CrudOperationsExample.java
package com.example.mongodb;
import com.mongodb.client.MongoClient;
import com.mongodb.client.MongoClients;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoDatabase;
import org.bson.Document;
import org.bson.types.ObjectId;
import java.util.ArrayList;
import java.util.List;
public class CrudOperationsExample {
public static void main(String[] args) {
String uri = "mongodb://localhost:27017";
try (MongoClient mongoClient = MongoClients.create(uri)) {
MongoDatabase database = mongoClient.getDatabase("mydb");
MongoCollection<Document> collection = database.getCollection("users");
// --- 1. 创建 ---
System.out.println("--- 创建文档 ---");
Document userDoc1 = new Document("name", "Alice")
.append("age", 30)
.append("city", "New York");
collection.insertOne(userDoc1);
System.out.println("插入文档1: " + userDoc1.getObjectId("_id"));
Document userDoc2 = new Document("name", "Bob")
.append("age", 25)
.append("city", "London");
collection.insertOne(userDoc2);
System.out.println("插入文档2: " + userDoc2.getObjectId("_id"));
// --- 2. 读取 ---
System.out.println("\n--- 读取所有文档 ---");
collection.find().forEach(doc -> System.out.println(doc.toJson()));
System.out.println("\n--- 按条件读取 (name = Alice) ---");
collection.find(new Document("name", "Alice")).forEach(doc -> System.out.println(doc.toJson()));
// --- 3. 更新 ---
System.out.println("\n--- 更新文档 (将 Alice 的年龄改为 31) ---");
collection.updateOne(
new Document("name", "Alice"),
new Document("$set", new Document("age", 31))
);
collection.find(new Document("name", "Alice")).forEach(doc -> System.out.println("更新后: " + doc.toJson()));
// --- 4. 删除 ---
System.out.println("\n--- 删除文档 (age = 25) ---");
collection.deleteOne(new Document("age", 25));
System.out.println("删除后所有文档:");
collection.find().forEach(doc -> System.out.println(doc.toJson()));
}
}
}
高级查询
MongoDB 的查询功能非常强大,使用 Filters 类可以方便地构建查询条件。
AdvancedQueriesExample.java
package com.example.mongodb;
import com.mongodb.client.MongoClient;
import com.mongodb.client.MongoClients;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoDatabase;
import com.mongodb.client.model.Filters;
import com.mongodb.client.model.Sorts;
import org.bson.Document;
import java.util.Arrays;
public class AdvancedQueriesExample {
public static void main(String[] args) {
String uri = "mongodb://localhost:27017";
try (MongoClient mongoClient = MongoClients.create(uri)) {
MongoDatabase database = mongoClient.getDatabase("mydb");
MongoCollection<Document> collection = database.getCollection("users");
// 准备一些测试数据
collection.insertMany(Arrays.asList(
new Document("name", "Charlie").append("age", 35).append("city", "Paris"),
new Document("name", "David").append("age", 28).append("city", "Berlin"),
new Document("name", "Eve").append("age", 35).append("city", "Paris"),
new Document("name", "Frank").append("age", 40).append("city", "Tokyo")
));
// 1. AND 查询: 年龄大于 30 且城市是 "Paris"
System.out.println("--- AND 查询 (age > 30 AND city = 'Paris') ---");
collection.find(Filters.and(
Filters.gt("age", 30),
Filters.eq("city", "Paris")
)).forEach(doc -> System.out.println(doc.toJson()));
// 2. OR 查询: 名字是 "David" 或者年龄小于 30
System.out.println("\n--- OR 查询 (name = 'David' OR age < 30) ---");
collection.find(Filters.or(
Filters.eq("name", "David"),
Filters.lt("age", 30)
)).forEach(doc -> System.out.println(doc.toJson()));
// 3. 排序: 按年龄升序
System.out.println("\n--- 按年龄升序排序 ---");
collection.find().sort(Sorts.ascending("age")).forEach(doc -> System.out.println(doc.toJson()));
// 4. 分页: 跳过前 2 个,获取接下来的 2 个
System.out.println("\n--- 分页 (Skip 2, Limit 2) ---");
collection.find().skip(2).limit(2).forEach(doc -> System.out.println(doc.toJson()));
// 清理数据
collection.deleteMany(new Document());
}
}
}
索引
索引用于提高查询性能,特别是在大型集合上。
IndexExample.java
package com.example.mongodb;
import com.mongodb.client.MongoClient;
import com.mongodb.client.MongoClients;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoDatabase;
import org.bson.Document;
public class IndexExample {
public static void main(String[] args) {
String uri = "mongodb://localhost:27017";
try (MongoClient mongoClient = MongoClients.create(uri)) {
MongoDatabase database = mongoClient.getDatabase("mydb");
MongoCollection<Document> collection = database.getCollection("users");
// 在 "city" 字段上创建一个升序索引
collection.createIndex(new Document("city", 1));
System.out.println("在 'city' 字段上创建索引成功。");
// 查看集合的所有索引
System.out.println("\n集合 'users' 的所有索引:");
collection.listIndexes().forEach(doc -> System.out.println(doc.toJson()));
}
}
}
聚合框架
聚合框架用于处理数据记录并返回计算结果,它类似于 SQL 中的 GROUP BY。
AggregationExample.java
package com.example.mongodb;
import com.mongodb.client.MongoClient;
import com.mongodb.client.MongoClients;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoDatabase;
import com.mongodb.client.model.Accumulators;
import com.mongodb.client.model.Aggregates;
import org.bson.Document;
import java.util.Arrays;
public class AggregationExample {
public static void main(String[] args) {
String uri = "mongodb://localhost:27017";
try (MongoClient mongoClient = MongoClients.create(uri)) {
MongoDatabase database = mongoClient.getDatabase("mydb");
MongoCollection<Document> collection = database.getCollection("users");
// 准备测试数据
collection.insertMany(Arrays.asList(
new Document("name", "Alice").append("department", "Sales").append("salary", 50000),
new Document("name", "Bob").append("department", "IT").append("salary", 60000),
new Document("name", "Charlie").append("department", "Sales").append("salary", 55000),
new Document("name", "David").append("department", "IT").append("salary", 70000)
));
// 聚合操作:按部门分组,并计算每个部门的平均薪资
System.out.println("--- 按部门分组并计算平均薪资 ---");
collection.aggregate(Arrays.asList(
// 第一阶段:按 department 字段分组
Aggregates.group("$department",
// 第二阶段:计算平均值
Accumulators.avg("averageSalary", "$salary")
)
)).forEach(doc -> System.out.println(doc.toJson()));
// 清理数据
collection.deleteMany(new Document());
}
}
}
完整项目示例
我们将所有部分整合到一个主类中,并使用 User POJO 来进行类型安全的操作,这需要使用 com.mongodb.client.model.InsertOneOptions 和 com.mongodb.client.result.UpdateResult 等来处理返回结果。
MainApplication.java
package com.example.mongodb;
import com.mongodb.client.MongoClient;
import com.mongodb.client.MongoClients;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoDatabase;
import com.mongodb.client.model.Filters;
import com.mongodb.client.model.Projections;
import com.mongodb.client.model.Sorts;
import com.mongodb.client.result.DeleteResult;
import com.mongodb.client.result.UpdateResult;
import org.bson.Document;
import org.bson.types.ObjectId;
import java.util.ArrayList;
import java.util.List;
public class MainApplication {
public static void main(String[] args) {
String uri = "mongodb://localhost:27017";
try (MongoClient mongoClient = MongoClients.create(uri)) {
MongoDatabase database = mongoClient.getDatabase("mydb");
MongoCollection<User> userCollection = database.getCollection("users_pojos", User.class);
// 清理旧数据,确保每次运行都是干净的
userCollection.deleteMany(new Document());
System.out.println("--- 1. 创建 (Insert) ---");
User user1 = new User();
user1.setName("Alice");
user1.setAge(30);
user1.setCity("New York");
userCollection.insertOne(user1);
System.out.println("插入成功: " + user1.getId());
User user2 = new User();
user2.setName("Bob");
user2.setAge(25);
user2.setCity("London");
userCollection.insertOne(user2);
System.out.println("插入成功: " + user2.getId());
User user3 = new User();
user3.setName("Charlie");
user3.setAge(30);
user3.setCity("Paris");
userCollection.insertOne(user3);
System.out.println("插入成功: " + user3.getId());
System.out.println("\n--- 2. 读取 (Find) ---");
System.out.println("查找所有用户:");
userCollection.find().forEach(System.out::println);
System.out.println("\n查找年龄为 30 的用户:");
userCollection.find(Filters.eq("age", 30)).forEach(System.out::println);
System.out.println("\n查找年龄大于 28 的用户,只返回名字和城市:");
userCollection.find(Filters.gt("age", 28))
.projection(Projections.fields(Projections.include("name", "city"), Projections.excludeId()))
.forEach(System.out::println);
System.out.println("\n--- 3. 更新 (Update) ---");
UpdateResult updateResult = userCollection.updateOne(
Filters.eq("name", "Alice"),
new Document("$set", new Document("age", 31))
);
System.out.println("更新了 " + updateResult.getModifiedCount() + " 个文档。");
System.out.println("更新后的 Alice: " + userCollection.find(Filters.eq("name", "Alice")).first());
System.out.println("\n--- 4. 删除 (Delete) ---");
DeleteResult deleteResult = userCollection.deleteOne(Filters.eq("name", "Bob"));
System.out.println("删除了 " + deleteResult.getDeletedCount() + " 个文档。");
System.out.println("删除后所有用户:");
userCollection.find().forEach(System.out::println);
System.out.println("\n--- 5. 高级查询与聚合 ---");
System.out.println("按年龄降序排序,并跳过第一个结果:");
userCollection.find().sort(Sorts.descending("age")).skip(1).forEach(System.out::println);
System.out.println("\n按年龄分组并计数:");
// 注意:对 POJO 集合进行聚合,需要将结果映射回 Document
userCollection.aggregate(
List.of(
new Document("$group", new Document("_id", "$age").append("count", new Document("$sum", 1)))
)
).forEach(doc -> System.out.println(doc.toJson()));
}
}
}
注意: 当使用泛型 MongoCollection<User.class> 时,驱动会自动进行 POJO 和 BSON 文档之间的转换,但在聚合管道中,中间结果仍然是 Document 类型,直到最后一步。
最佳实践
-
连接管理:
- 使用
try-with-resources: 始终将MongoClient包装在try-with-resources语句中,以确保连接被正确关闭。 - 不要为每个请求创建新的
MongoClient:MongoClient是线程安全的,并且内部管理着连接池,你的整个应用应该只创建一个MongoClient实例,并在其生命周期内重复使用它。
- 使用
-
异常处理:
- 捕获
MongoException或其子类,以处理网络问题、服务器错误等。
- 捕获
-
文档映射:
- 对于结构化的数据,使用 POJO (如
User类) 是一个好习惯,它提供了类型安全,使代码更易于维护。 - 驱动支持 JSON-B、Jackson 等标准进行映射。
- 对于结构化的数据,使用 POJO (如
-
索引策略:
- 为经常用于查询、排序和分组的字段创建索引。
- 使用
explain()方法分析查询性能,确保你的索引被正确使用。
-
安全性:
- 在生产环境中,永远不要在连接字符串中硬编码用户名和密码,使用环境变量或配置文件。
- 启用 MongoDB 的认证机制。
- 对敏感数据进行加密。
-
考虑 Spring Data MongoDB:
- 对于更复杂的项目,特别是已经使用 Spring 框架的项目,强烈推荐使用 Spring Data MongoDB。
- 它提供了更高层次的抽象,如
Repository接口,让你可以用类似 JPA 的方式操作 MongoDB,极大地简化了数据访问层的代码。
这个指南为你提供了一个从零开始的 MongoDB Java 项目的坚实基础,你可以基于此进行扩展,构建更复杂的应用程序。
