杰瑞科技汇

MongoDB Java对象如何映射与操作?

MongoDB 官方提供了一个强大的 Java 驱动程序,它提供了两种主要的操作方式:

MongoDB Java对象如何映射与操作?-图1
(图片来源网络,侵删)
  1. MongoDB Java Driver (原生 API):直接使用驱动提供的 MongoCollection, Filters, Projections 等类来构建查询和操作,这是最底层、最灵活的方式。
  2. Spring Data MongoDB:在原生驱动之上构建,提供了类似 Spring Data JPA 的编程模型,如 Repository 接口,极大地简化了数据访问层的代码,这是目前企业级应用中最主流的方式。

下面我将分别介绍这两种方式,并提供一个完整的、可运行的示例。


核心概念:Bson vs. POJO

在深入代码之前,必须理解两个关键概念:

  • BSON (Binary JSON):MongoDB 存储的数据格式,在 Java 驱动中,它被表示为 org.bson.Document 或其他实现了 Bson 接口的类,你可以把它看作一个通用的、键值对的集合,类似于 Map<String, Object>
  • POJO (Plain Old Java Object):普通的 Java 对象,也就是我们业务逻辑中常用的实体类,如 User, Product 等。

MongoDB 驱动需要在 BsonPOJO 之间进行转换。

  • 序列化:将 POJO 转换为 BSON (存入数据库)。
  • 反序列化:将 BSON 转换为 POJO (从数据库读取)。

驱动程序会使用反射机制,通过 POJO 的字段名和 BSON 的键名进行匹配。

MongoDB Java对象如何映射与操作?-图2
(图片来源网络,侵删)

使用原生 MongoDB Java Driver

这种方式让你完全控制查询的构建过程,适合学习底层原理或需要编写复杂、高性能查询的场景。

准备工作:添加依赖

如果你使用 Maven,在 pom.xml 中添加依赖:

<dependencies>
    <!-- MongoDB Java Driver -->
    <dependency>
        <groupId>org.mongodb</groupId>
        <artifactId>mongodb-driver-sync</artifactId>
        <version>4.11.1</version> <!-- 请使用最新版本 -->
    </dependency>
    <!-- 为了方便打印 JSON,可以添加这个 -->
    <dependency>
        <groupId>org.mongodb</groupId>
        <artifactId>bson</artifactId>
        <version>4.11.1</version>
    </dependency>
</dependencies>

创建 POJO 类

创建一个与 MongoDB 集合对应的 Java 类。

// src/main/java/com/example/User.java
package com.example;
import org.bson.types.ObjectId;
import java.util.Date;
// @Document 注解在原生驱动中不是必须的,但有助于代码清晰
public class User {
    // 使用 ObjectId 作为主键,对应 MongoDB 的 _id
    private ObjectId id;
    private String name;
    private int age;
    private Date registrationDate;
    private String[] hobbies; // 数组类型
    // 无参构造函数是反序列化所必需的
    public User() {}
    // 全参构造函数 (可选,但推荐)
    public User(String name, int age, Date registrationDate, String[] hobbies) {
        this.name = name;
        this.age = age;
        this.registrationDate = registrationDate;
        this.hobbies = hobbies;
    }
    // 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 Date getRegistrationDate() { return registrationDate; }
    public void setRegistrationDate(Date registrationDate) { this.registrationDate = registrationDate; }
    public String[] getHobbies() { return hobbies; }
    public void setHobbies(String[] hobbies) { this.hobbies = hobbies; }
    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", age=" + age +
                ", registrationDate=" + registrationDate +
                ", hobbies=" + String.join(", ", hobbies) +
                '}';
    }
}

编写代码进行 CRUD 操作

// src/main/java/com/example/MongoNativeExample.java
package com.example;
import com.mongodb.client.*;
import com.mongodb.client.model.*;
import org.bson.Document;
import org.bson.types.ObjectId;
import java.util.Arrays;
import java.util.Date;
public class MongoNativeExample {
    public static void main(String[] args) {
        // 1. 创建 MongoClient,连接到本地 MongoDB 服务
        String uri = "mongodb://localhost:27017";
        try (MongoClient mongoClient = MongoClients.create(uri)) {
            // 2. 获取数据库,如果不存在会自动创建
            MongoDatabase database = mongoClient.getDatabase("testdb");
            // 3. 获取集合,如果不存在会自动创建
            MongoCollection<Document> collection = database.getCollection("users");
            // --- 插入单个文档 ---
            System.out.println("--- 插入单个文档 ---");
            User newUser = new User("Alice", 30, new Date(), new String[]{"Reading", "Hiking"});
            // 将 POJO 转换为 Document
            Document docToInsert = Document.parse(com.mongodb.client.model.Converters.toDocument(newUser));
            collection.insertOne(docToInsert);
            System.out.println("插入成功: " + docToInsert.toJson());
            // --- 插入多个文档 ---
            System.out.println("\n--- 插入多个文档 ---");
            User user2 = new User("Bob", 25, new Date(), new String[]{"Gaming", "Cooking"});
            User user3 = new User("Charlie", 35, new Date(), new String[]{"Coding", "Swimming"});
            collection.insertMany(Arrays.asList(
                    Document.parse(com.mongodb.client.model.Converters.toDocument(user2)),
                    Document.parse(com.mongodb.client.model.Converters.toDocument(user3))
            ));
            System.out.println("批量插入成功");
            // --- 查询所有文档 ---
            System.out.println("\n--- 查询所有文档 ---");
            // FindIterable<Document> 是惰性的,只有迭代时才会执行查询
            FindIterable<Document> findIterable = collection.find();
            MongoCursor<Document> cursor = findIterable.iterator();
            try {
                while (cursor.hasNext()) {
                    System.out.println(cursor.next().toJson());
                }
            } finally {
                cursor.close(); // 必须关闭 cursor
            }
            // --- 查询特定文档 (使用 Filters) ---
            System.out.println("\n--- 查询名为 'Alice' 的用户 ---");
            // 将查询结果直接映射为 User 对象列表
            FindIterable<User> findIterableUser = collection.find(Filters.eq("name", "Alice"), User.class);
            MongoCursor<User> userCursor = findIterableUser.iterator();
            try {
                while (userCursor.hasNext()) {
                    System.out.println("查询结果 (POJO): " + userCursor.next());
                }
            } finally {
                userCursor.close();
            }
            // --- 更新文档 ---
            System.out.println("\n--- 更新 Bob 的年龄 ---");
            // 更新第一个匹配的文档
            collection.updateOne(
                    Filters.eq("name", "Bob"),
                    Updates.set("age", 26)
            );
            System.out.println("更新成功");
            // --- 删除文档 ---
            System.out.println("\n--- 删除名为 Charlie 的用户 ---");
            DeleteResult deleteResult = collection.deleteOne(Filters.eq("name", "Charlie"));
            System.out.println("删除了 " + deleteResult.getDeletedCount() + " 个文档");
            // --- 清理集合 (可选) ---
            // collection.drop(); // 删除整个集合
        }
    }
}

使用 Spring Data MongoDB (推荐)

这是更现代、更简洁的方式,尤其适合构建 Spring Boot 应用。

准备工作:添加依赖

在 Spring Boot 项目的 pom.xml 中,通常只需要一个 spring-boot-starter-data-mongodb 依赖即可。

<dependencies>
    <!-- Spring Boot Starter for MongoDB -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-mongodb</artifactId>
    </dependency>
    <!-- Spring Boot Starter Test -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
</dependencies>

配置连接

application.propertiesapplication.yml 中配置 MongoDB 连接信息。

application.properties:

spring.data.mongodb.uri=mongodb://localhost:27017/testdb

application.yml:

spring:
  data:
    mongodb:
      uri: mongodb://localhost:27017/testdb

创建 POJO 类 (与原生驱动相同)

这个 User.java 类和上面的一模一样。

创建 Repository 接口

这是 Spring Data 的核心,你只需要定义一个接口,继承 MongoRepository,Spring Data 会自动为你实现所有 CRUD 方法。

// src/main/java/com/example/UserRepository.java
package com.example;
import org.springframework.data.mongodb.repository.MongoRepository;
import org.springframework.stereotype.Repository;
import java.util.List;
@Repository
public interface UserRepository extends MongoRepository<User, String> {
    // Spring Data 会根据方法名自动生成查询
    // 查询所有年龄大于指定值的用户
    List<User> findByAgeGreaterThan(int age);
    // 查询名字为指定值的用户
    User findByName(String name);
}
  • MongoRepository<T, ID>T 是实体类型 (User),ID 是主键类型 (String,因为 ObjectId 可以被当作 String 处理)。
  • 方法名解析:findBy... 是约定,GreaterThan 是查询条件。

创建 Service 和 Controller 来使用 Repository

// src/main/java/com/example/UserService.java
package com.example;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class UserService {
    @Autowired
    private UserRepository userRepository;
    public User saveUser(User user) {
        return userRepository.save(user);
    }
    public List<User> getAllUsers() {
        return userRepository.findAll();
    }
    public User getUserByName(String name) {
        return userRepository.findByName(name);
    }
    public List<User> getUsersOlderThan(int age) {
        return userRepository.findByAgeGreaterThan(age);
    }
    public void deleteUser(String id) {
        userRepository.deleteById(id);
    }
}

创建一个简单的应用类来测试

// src/main/java/com/example/MongoSpringApplication.java
package com.example;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
@SpringBootApplication
public class MongoSpringApplication {
    public static void main(String[] args) {
        SpringApplication.run(MongoSpringApplication.class, args);
    }
    // CommandLineRunner 会在应用启动后自动执行
    @Bean
    public CommandLineRunner run(UserRepository repository, MongoTemplate mongoTemplate) {
        return args -> {
            System.out.println("--- Spring Data MongoDB 示例开始 ---");
            // 使用 MongoTemplate 进行更复杂的查询 (可选)
            // mongoTemplate.insert(new User("David", 40, new Date(), new String[]{"Fishing"}), "users");
            // 1. 保存
            System.out.println("\n1. 保存用户...");
            User user1 = repository.save(new User("Eve", 28, new Date(), new String[]{"Painting", "Dancing"}));
            User user2 = repository.save(new User("Frank", 45, new Date(), new String[]{"Gardening"}));
            System.out.println("保存成功: " + user1.getName() + ", " + user2.getName());
            // 2. 查询所有
            System.out.println("\n2. 查询所有用户...");
            List<User> allUsers = repository.findAll();
            allUsers.forEach(System.out::println);
            // 3. 使用自定义方法查询
            System.out.println("\n3. 查询年龄大于 30 的用户...");
            List<User> olderUsers = repository.findByAgeGreaterThan(30);
            olderUsers.forEach(System.out::println);
            // 4. 根据名字查询
            System.out.println("\n4. 根据 'Eve' 查询用户...");
            User foundUser = repository.findByName("Eve");
            System.out.println("找到用户: " + foundUser);
            // 5. 删除
            System.out.println("\n5. 删除用户 'Frank'...");
            repository.deleteById(user2.getId());
            System.out.println("删除成功");
            System.out.println("剩余用户: " + repository.findAll().size());
        };
    }
}

总结与对比

特性 原生 Java Driver Spring Data MongoDB
易用性 较低,需要手动构建查询和转换对象 非常高,通过接口和约定简化大量代码
灵活性 极高,可以构建任何复杂的查询和命令 较高,但受限于 Repository 接口和 MongoTemplate 的能力
学习曲线 陡峭,需要理解 MongoDB 的底层 API 平缓,尤其对 Spring 框架熟悉的开发者
适用场景 学习、性能关键型应用、复杂查询脚本 绝大多数企业级应用、快速开发、微服务
依赖 mongodb-driver-sync spring-boot-starter-data-mongodb

建议

  • 新手或快速开发:直接使用 Spring Data MongoDB,它能让你专注于业务逻辑,而不是数据库连接和查询细节。
  • 深入理解或特殊需求:从 原生驱动 开始学习,了解其工作原理,当你需要编写无法通过 Repository 实现的复杂查询时,可以在 Spring 项目中注入 MongoTemplate 来使用原生驱动的功能。
分享:
扫描分享到社交APP
上一篇
下一篇