MongoDB 详细用法与 Java 集成完整指南

发布于:2025-08-02 ⋅ 阅读:(11) ⋅ 点赞:(0)

MongoDB 详细用法与 Java 集成完整指南

目录

  1. MongoDB 基础概念
  2. MongoDB 安装与配置
  3. MongoDB Shell 基本操作
  4. Java 环境准备
  5. Java MongoDB 驱动集成
  6. 连接配置
  7. 基本 CRUD 操作
  8. 高级查询操作
  9. 索引操作
  10. 聚合管道
  11. 事务处理
  12. Spring Boot 集成
  13. 最佳实践

1. MongoDB 基础概念

1.1 核心概念对比

SQL术语 MongoDB术语 说明
database database 数据库
table collection 集合(表)
row document 文档(行)
column field 字段(列)
index index 索引
primary key _id 主键

1.2 文档结构

{
  "_id": ObjectId("507f1f77bcf86cd799439011"),
  "name": "John Doe",
  "age": 30,
  "email": "john@example.com",
  "address": {
    "street": "123 Main St",
    "city": "New York",
    "zipcode": "10001"
  },
  "tags": ["developer", "mongodb", "java"],
  "createdAt": ISODate("2023-01-01T00:00:00Z")
}

2. MongoDB 安装与配置

2.1 Windows 安装

# 1. 下载 MongoDB Community Server
# https://www.mongodb.com/try/download/community

# 2. 安装后启动服务
net start MongoDB

# 3. 连接到 MongoDB
mongo

2.2 Linux 安装 (Ubuntu)

# 1. 导入公钥
wget -qO - https://www.mongodb.org/static/pgp/server-6.0.asc | sudo apt-key add -

# 2. 添加仓库
echo "deb [ arch=amd64,arm64 ] https://repo.mongodb.org/apt/ubuntu focal/mongodb-org/6.0 multiverse" | sudo tee /etc/apt/sources.list.d/mongodb-org-6.0.list

# 3. 更新包列表并安装
sudo apt-get update
sudo apt-get install -y mongodb-org

# 4. 启动服务
sudo systemctl start mongod
sudo systemctl enable mongod

# 5. 验证安装
mongosh

2.3 Docker 安装

# 拉取 MongoDB 镜像
docker pull mongo:latest

# 运行 MongoDB 容器
docker run -d \
  --name mongodb \
  -p 27017:27017 \
  -e MONGO_INITDB_ROOT_USERNAME=admin \
  -e MONGO_INITDB_ROOT_PASSWORD=password \
  -v mongodb_data:/data/db \
  mongo:latest

# 连接到容器
docker exec -it mongodb mongosh -u admin -p password

3. MongoDB Shell 基本操作

3.1 数据库操作

// 显示所有数据库
show dbs

// 使用/创建数据库
use myapp

// 显示当前数据库
db

// 删除数据库
db.dropDatabase()

3.2 集合操作

// 显示所有集合
show collections

// 创建集合
db.createCollection("users")

// 删除集合
db.users.drop()

3.3 文档操作

// 插入单个文档
db.users.insertOne({
  name: "Alice",
  age: 25,
  email: "alice@example.com"
})

// 插入多个文档
db.users.insertMany([
  { name: "Bob", age: 30, email: "bob@example.com" },
  { name: "Charlie", age: 35, email: "charlie@example.com" }
])

// 查询所有文档
db.users.find()

// 条件查询
db.users.find({ age: { $gte: 30 } })

// 更新文档
db.users.updateOne(
  { name: "Alice" },
  { $set: { age: 26 } }
)

// 删除文档
db.users.deleteOne({ name: "Bob" })

4. Java 环境准备

4.1 系统要求

  • Java 8 或更高版本
  • Maven 3.3+ 或 Gradle 4.0+
  • MongoDB 4.0 或更高版本

4.2 Maven 项目结构

my-mongodb-app/
├── pom.xml
├── src/
│   ├── main/
│   │   ├── java/
│   │   │   └── com/
│   │   │       └── example/
│   │   │           ├── Main.java
│   │   │           ├── config/
│   │   │           ├── model/
│   │   │           ├── dao/
│   │   │           └── service/
│   │   └── resources/
│   │       └── application.properties
│   └── test/
└── target/

5. Java MongoDB 驱动集成

5.1 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-example</artifactId>
    <version>1.0.0</version>
    <packaging>jar</packaging>
    
    <properties>
        <maven.compiler.source>11</maven.compiler.source>
        <maven.compiler.target>11</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>
    
    <dependencies>
        <!-- MongoDB Java Driver -->
        <dependency>
            <groupId>org.mongodb</groupId>
            <artifactId>mongodb-driver-sync</artifactId>
            <version>4.11.1</version>
        </dependency>
        
        <!-- 可选: 异步驱动 -->
        <dependency>
            <groupId>org.mongodb</groupId>
            <artifactId>mongodb-driver-reactivestreams</artifactId>
            <version>4.11.1</version>
        </dependency>
        
        <!-- JSON 处理 -->
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.15.2</version>
        </dependency>
        
        <!-- 日志 -->
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-simple</artifactId>
            <version>2.0.7</version>
        </dependency>
        
        <!-- 测试 -->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.13.2</version>
            <scope>test</scope>
        </dependency>
    </dependencies>
    
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.11.0</version>
                <configuration>
                    <source>11</source>
                    <target>11</target>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

5.2 Gradle 依赖配置

plugins {
    id 'java'
    id 'application'
}

group = 'com.example'
version = '1.0.0'
sourceCompatibility = '11'

repositories {
    mavenCentral()
}

dependencies {
    // MongoDB Java Driver
    implementation 'org.mongodb:mongodb-driver-sync:4.11.1'
    implementation 'org.mongodb:mongodb-driver-reactivestreams:4.11.1'
    
    // JSON 处理
    implementation 'com.fasterxml.jackson.core:jackson-databind:2.15.2'
    
    // 日志
    implementation 'org.slf4j:slf4j-simple:2.0.7'
    
    // 测试
    testImplementation 'junit:junit:4.13.2'
}

application {
    mainClass = 'com.example.Main'
}

6. 连接配置

6.1 基本连接配置

package com.example.config;

import com.mongodb.client.MongoClient;
import com.mongodb.client.MongoClients;
import com.mongodb.client.MongoDatabase;
import com.mongodb.ConnectionString;
import com.mongodb.MongoClientSettings;
import com.mongodb.ServerAddress;
import com.mongodb.MongoCredential;
import java.util.Arrays;

public class MongoDBConfig {
    
    private static final String DATABASE_NAME = "myapp";
    private static final String CONNECTION_STRING = "mongodb://localhost:27017";
    
    private static MongoClient mongoClient;
    private static MongoDatabase database;
    
    // 简单连接方式
    public static MongoDatabase getDatabase() {
        if (database == null) {
            mongoClient = MongoClients.create(CONNECTION_STRING);
            database = mongoClient.getDatabase(DATABASE_NAME);
        }
        return database;
    }
    
    // 详细连接配置
    public static MongoDatabase getDatabaseWithOptions() {
        if (database == null) {
            // 创建连接字符串
            ConnectionString connectionString = new ConnectionString(
                "mongodb://username:password@localhost:27017/myapp?authSource=admin"
            );
            
            // 或者使用 MongoClientSettings 进行详细配置
            MongoClientSettings settings = MongoClientSettings.builder()
                .applyConnectionString(connectionString)
                .retryWrites(true)
                .build();
                
            mongoClient = MongoClients.create(settings);
            database = mongoClient.getDatabase(DATABASE_NAME);
        }
        return database;
    }
    
    // 集群连接配置
    public static MongoDatabase getClusterDatabase() {
        if (database == null) {
            // 服务器地址列表
            ServerAddress seed1 = new ServerAddress("server1.example.com", 27017);
            ServerAddress seed2 = new ServerAddress("server2.example.com", 27017);
            ServerAddress seed3 = new ServerAddress("server3.example.com", 27017);
            
            // 认证信息
            MongoCredential credential = MongoCredential.createCredential(
                "username", "admin", "password".toCharArray()
            );
            
            // 客户端设置
            MongoClientSettings settings = MongoClientSettings.builder()
                .applyToClusterSettings(builder -> 
                    builder.hosts(Arrays.asList(seed1, seed2, seed3)))
                .credential(credential)
                .build();
                
            mongoClient = MongoClients.create(settings);
            database = mongoClient.getDatabase(DATABASE_NAME);
        }
        return database;
    }
    
    // 关闭连接
    public static void close() {
        if (mongoClient != null) {
            mongoClient.close();
        }
    }
}

6.2 连接池配置

package com.example.config;

import com.mongodb.ConnectionString;
import com.mongodb.MongoClientSettings;
import com.mongodb.client.MongoClient;
import com.mongodb.client.MongoClients;
import com.mongodb.connection.ConnectionPoolSettings;
import java.util.concurrent.TimeUnit;

public class ConnectionPoolConfig {
    
    public static MongoClient createMongoClientWithPool() {
        ConnectionString connectionString = new ConnectionString(
            "mongodb://localhost:27017/myapp"
        );
        
        // 连接池设置
        ConnectionPoolSettings poolSettings = ConnectionPoolSettings.builder()
            .maxSize(20)                    // 最大连接数
            .minSize(5)                     // 最小连接数
            .maxWaitTime(2, TimeUnit.MINUTES) // 最大等待时间
            .maxConnectionLifeTime(30, TimeUnit.MINUTES) // 连接最大生存时间
            .maxConnectionIdleTime(10, TimeUnit.MINUTES) // 连接最大空闲时间
            .build();
        
        MongoClientSettings settings = MongoClientSettings.builder()
            .applyConnectionString(connectionString)
            .applyToConnectionPoolSettings(builder -> 
                builder.applySettings(poolSettings))
            .build();
            
        return MongoClients.create(settings);
    }
}

7. 基本 CRUD 操作

7.1 实体类定义

package com.example.model;

import org.bson.types.ObjectId;
import com.fasterxml.jackson.annotation.JsonProperty;
import java.time.LocalDateTime;
import java.util.List;

public class User {
    
    @JsonProperty("_id")
    private ObjectId id;
    
    private String name;
    private String email;
    private Integer age;
    private Address address;
    private List<String> tags;
    private LocalDateTime createdAt;
    private LocalDateTime updatedAt;
    
    // 构造函数
    public User() {
        this.createdAt = LocalDateTime.now();
    }
    
    public User(String name, String email, Integer age) {
        this();
        this.name = name;
        this.email = email;
        this.age = age;
    }
    
    // Getter 和 Setter 方法
    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 String getEmail() { return email; }
    public void setEmail(String email) { this.email = email; }
    
    public Integer getAge() { return age; }
    public void setAge(Integer age) { this.age = age; }
    
    public Address getAddress() { return address; }
    public void setAddress(Address address) { this.address = address; }
    
    public List<String> getTags() { return tags; }
    public void setTags(List<String> tags) { this.tags = tags; }
    
    public LocalDateTime getCreatedAt() { return createdAt; }
    public void setCreatedAt(LocalDateTime createdAt) { this.createdAt = createdAt; }
    
    public LocalDateTime getUpdatedAt() { return updatedAt; }
    public void setUpdatedAt(LocalDateTime updatedAt) { this.updatedAt = updatedAt; }
    
    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", email='" + email + '\'' +
                ", age=" + age +
                ", address=" + address +
                ", tags=" + tags +
                ", createdAt=" + createdAt +
                ", updatedAt=" + updatedAt +
                '}';
    }
}

// 地址类
class Address {
    private String street;
    private String city;
    private String zipcode;
    private String country;
    
    // 构造函数
    public Address() {}
    
    public Address(String street, String city, String zipcode, String country) {
        this.street = street;
        this.city = city;
        this.zipcode = zipcode;
        this.country = country;
    }
    
    // Getter 和 Setter 方法
    public String getStreet() { return street; }
    public void setStreet(String street) { this.street = street; }
    
    public String getCity() { return city; }
    public void setCity(String city) { this.city = city; }
    
    public String getZipcode() { return zipcode; }
    public void setZipcode(String zipcode) { this.zipcode = zipcode; }
    
    public String getCountry() { return country; }
    public void setCountry(String country) { this.country = country; }
    
    @Override
    public String toString() {
        return "Address{" +
                "street='" + street + '\'' +
                ", city='" + city + '\'' +
                ", zipcode='" + zipcode + '\'' +
                ", country='" + country + '\'' +
                '}';
    }
}

7.2 DAO 层实现

package com.example.dao;

import com.example.config.MongoDBConfig;
import com.example.model.User;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoDatabase;
import com.mongodb.client.model.Filters;
import com.mongodb.client.model.Updates;
import com.mongodb.client.model.Sorts;
import com.mongodb.client.model.Projections;
import com.mongodb.client.result.InsertOneResult;
import com.mongodb.client.result.UpdateResult;
import com.mongodb.client.result.DeleteResult;
import org.bson.Document;
import org.bson.conversions.Bson;
import org.bson.types.ObjectId;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;

public class UserDAO {
    
    private final MongoCollection<Document> collection;
    
    public UserDAO() {
        MongoDatabase database = MongoDBConfig.getDatabase();
        this.collection = database.getCollection("users");
    }
    
    // 创建用户 - 插入单个文档
    public ObjectId createUser(User user) {
        try {
            Document doc = userToDocument(user);
            InsertOneResult result = collection.insertOne(doc);
            return result.getInsertedId().asObjectId().getValue();
        } catch (Exception e) {
            throw new RuntimeException("Error creating user: " + e.getMessage(), e);
        }
    }
    
    // 批量创建用户
    public List<ObjectId> createUsers(List<User> users) {
        try {
            List<Document> documents = new ArrayList<>();
            for (User user : users) {
                documents.add(userToDocument(user));
            }
            
            collection.insertMany(documents);
            
            List<ObjectId> insertedIds = new ArrayList<>();
            for (Document doc : documents) {
                insertedIds.add(doc.getObjectId("_id"));
            }
            return insertedIds;
            
        } catch (Exception e) {
            throw new RuntimeException("Error creating users: " + e.getMessage(), e);
        }
    }
    
    // 根据 ID 查询用户
    public User findById(ObjectId id) {
        try {
            Document doc = collection.find(Filters.eq("_id", id)).first();
            return doc != null ? documentToUser(doc) : null;
        } catch (Exception e) {
            throw new RuntimeException("Error finding user by id: " + e.getMessage(), e);
        }
    }
    
    // 根据邮箱查询用户
    public User findByEmail(String email) {
        try {
            Document doc = collection.find(Filters.eq("email", email)).first();
            return doc != null ? documentToUser(doc) : null;
        } catch (Exception e) {
            throw new RuntimeException("Error finding user by email: " + e.getMessage(), e);
        }
    }
    
    // 查询所有用户
    public List<User> findAll() {
        try {
            List<User> users = new ArrayList<>();
            for (Document doc : collection.find()) {
                users.add(documentToUser(doc));
            }
            return users;
        } catch (Exception e) {
            throw new RuntimeException("Error finding all users: " + e.getMessage(), e);
        }
    }
    
    // 条件查询 - 年龄范围
    public List<User> findByAgeRange(int minAge, int maxAge) {
        try {
            List<User> users = new ArrayList<>();
            Bson filter = Filters.and(
                Filters.gte("age", minAge),
                Filters.lte("age", maxAge)
            );
            
            for (Document doc : collection.find(filter)) {
                users.add(documentToUser(doc));
            }
            return users;
        } catch (Exception e) {
            throw new RuntimeException("Error finding users by age range: " + e.getMessage(), e);
        }
    }
    
    // 模糊查询 - 姓名包含关键词
    public List<User> findByNameContaining(String keyword) {
        try {
            List<User> users = new ArrayList<>();
            Bson filter = Filters.regex("name", ".*" + keyword + ".*", "i");
            
            for (Document doc : collection.find(filter)) {
                users.add(documentToUser(doc));
            }
            return users;
        } catch (Exception e) {
            throw new RuntimeException("Error finding users by name: " + e.getMessage(), e);
        }
    }
    
    // 分页查询
    public List<User> findWithPagination(int page, int pageSize) {
        try {
            List<User> users = new ArrayList<>();
            int skip = (page - 1) * pageSize;
            
            for (Document doc : collection.find()
                    .sort(Sorts.descending("createdAt"))
                    .skip(skip)
                    .limit(pageSize)) {
                users.add(documentToUser(doc));
            }
            return users;
        } catch (Exception e) {
            throw new RuntimeException("Error finding users with pagination: " + e.getMessage(), e);
        }
    }
    
    // 只查询特定字段
    public List<User> findNamesAndEmails() {
        try {
            List<User> users = new ArrayList<>();
            Bson projection = Projections.fields(
                Projections.include("name", "email"),
                Projections.exclude("_id")
            );
            
            for (Document doc : collection.find().projection(projection)) {
                User user = new User();
                user.setName(doc.getString("name"));
                user.setEmail(doc.getString("email"));
                users.add(user);
            }
            return users;
        } catch (Exception e) {
            throw new RuntimeException("Error finding names and emails: " + e.getMessage(), e);
        }
    }
    
    // 更新用户
    public boolean updateUser(ObjectId id, User user) {
        try {
            user.setUpdatedAt(LocalDateTime.now());
            
            Bson filter = Filters.eq("_id", id);
            Bson update = Updates.combine(
                Updates.set("name", user.getName()),
                Updates.set("email", user.getEmail()),
                Updates.set("age", user.getAge()),
                Updates.set("updatedAt", user.getUpdatedAt())
            );
            
            UpdateResult result = collection.updateOne(filter, update);
            return result.getModifiedCount() > 0;
        } catch (Exception e) {
            throw new RuntimeException("Error updating user: " + e.getMessage(), e);
        }
    }
    
    // 部分更新 - 只更新年龄
    public boolean updateAge(ObjectId id, int newAge) {
        try {
            Bson filter = Filters.eq("_id", id);
            Bson update = Updates.combine(
                Updates.set("age", newAge),
                Updates.set("updatedAt", LocalDateTime.now())
            );
            
            UpdateResult result = collection.updateOne(filter, update);
            return result.getModifiedCount() > 0;
        } catch (Exception e) {
            throw new RuntimeException("Error updating user age: " + e.getMessage(), e);
        }
    }
    
    // 批量更新
    public long updateUsersInCity(String city, String newCountry) {
        try {
            Bson filter = Filters.eq("address.city", city);
            Bson update = Updates.combine(
                Updates.set("address.country", newCountry),
                Updates.set("updatedAt", LocalDateTime.now())
            );
            
            UpdateResult result = collection.updateMany(filter, update);
            return result.getModifiedCount();
        } catch (Exception e) {
            throw new RuntimeException("Error updating users in city: " + e.getMessage(), e);
        }
    }
    
    // 删除用户
    public boolean deleteUser(ObjectId id) {
        try {
            DeleteResult result = collection.deleteOne(Filters.eq("_id", id));
            return result.getDeletedCount() > 0;
        } catch (Exception e) {
            throw new RuntimeException("Error deleting user: " + e.getMessage(), e);
        }
    }
    
    // 根据条件删除多个用户
    public long deleteUsersByAge(int maxAge) {
        try {
            Bson filter = Filters.lte("age", maxAge);
            DeleteResult result = collection.deleteMany(filter);
            return result.getDeletedCount();
        } catch (Exception e) {
            throw new RuntimeException("Error deleting users by age: " + e.getMessage(), e);
        }
    }
    
    // 计数操作
    public long countUsers() {
        try {
            return collection.countDocuments();
        } catch (Exception e) {
            throw new RuntimeException("Error counting users: " + e.getMessage(), e);
        }
    }
    
    public long countUsersByAge(int minAge) {
        try {
            return collection.countDocuments(Filters.gte("age", minAge));
        } catch (Exception e) {
            throw new RuntimeException("Error counting users by age: " + e.getMessage(), e);
        }
    }
    
    // 辅助方法 - User 转 Document
    private Document userToDocument(User user) {
        Document doc = new Document();
        
        if (user.getId() != null) {
            doc.put("_id", user.getId());
        }
        
        doc.put("name", user.getName());
        doc.put("email", user.getEmail());
        doc.put("age", user.getAge());
        
        if (user.getAddress() != null) {
            Document addressDoc = new Document()
                .append("street", user.getAddress().getStreet())
                .append("city", user.getAddress().getCity())
                .append("zipcode", user.getAddress().getZipcode())
                .append("country", user.getAddress().getCountry());
            doc.put("address", addressDoc);
        }
        
        if (user.getTags() != null) {
            doc.put("tags", user.getTags());
        }
        
        doc.put("createdAt", user.getCreatedAt());
        doc.put("updatedAt", user.getUpdatedAt());
        
        return doc;
    }
    
    // 辅助方法 - Document 转 User
    private User documentToUser(Document doc) {
        User user = new User();
        
        user.setId(doc.getObjectId("_id"));
        user.setName(doc.getString("name"));
        user.setEmail(doc.getString("email"));
        user.setAge(doc.getInteger("age"));
        
        Document addressDoc = doc.get("address", Document.class);
        if (addressDoc != null) {
            Address address = new Address(
                addressDoc.getString("street"),
                addressDoc.getString("city"),
                addressDoc.getString("zipcode"),
                addressDoc.getString("country")
            );
            user.setAddress(address);
        }
        
        @SuppressWarnings("unchecked")
        List<String> tags = doc.get("tags", List.class);
        user.setTags(tags);
        
        // 注意:这里需要处理日期类型转换
        user.setCreatedAt((LocalDateTime) doc.get("createdAt"));
        user.setUpdatedAt((LocalDateTime) doc.get("updatedAt"));
        
        return user;
    }
}

7.3 Service 层实现

package com.example.service;

import com.example.dao.UserDAO;
import com.example.model.User;
import org.bson.types.ObjectId;

import java.util.List;

public class UserService {
    
    private final UserDAO userDAO;
    
    public UserService() {
        this.userDAO = new UserDAO();
    }
    
    // 创建用户
    public ObjectId createUser(String name, String email, Integer age) {
        // 业务逻辑验证
        if (name == null || name.trim().isEmpty()) {
            throw new IllegalArgumentException("Name cannot be empty");
        }
        
        if (email == null || !isValidEmail(email)) {
            throw new IllegalArgumentException("Invalid email format");
        }
        
        if (age != null && (age < 0 || age > 150)) {
            throw new IllegalArgumentException("Age must be between 0 and 150");
        }
        
        // 检查邮箱是否已存在
        User existingUser = userDAO.findByEmail(email);
        if (existingUser != null) {
            throw new IllegalArgumentException("Email already exists");
        }
        
        User user = new User(name, email, age);
        return userDAO.createUser(user);
    }
    
    // 获取用户
    public User getUserById(String id) {
        try {
            ObjectId objectId = new ObjectId(id);
            return userDAO.findById(objectId);
        } catch (IllegalArgumentException e) {
            throw new IllegalArgumentException("Invalid user ID format");
        }
    }
    
    public User getUserByEmail(String email) {
        return userDAO.findByEmail(email);
    }
    
    public List<User> getAllUsers() {
        return userDAO.findAll();
    }
    
    public List<User> getUsersByAgeRange(int minAge, int maxAge) {
        if (minAge < 0 || maxAge < 0 || minAge > maxAge) {
            throw new IllegalArgumentException("Invalid age range");
        }
        return userDAO.findByAgeRange(minAge, maxAge);
    }
    
    public List<User> searchUsersByName(String keyword) {
        if (keyword == null || keyword.trim().isEmpty()) {
            throw new IllegalArgumentException("Search keyword cannot be empty");
        }
        return userDAO.findByNameContaining(keyword.trim());
    }
    
    public List<User> getUsersWithPagination(int page, int pageSize) {
        if (page < 1 || pageSize < 1) {
            throw new IllegalArgumentException("Page and pageSize must be positive");
        }
        return userDAO.findWithPagination(page, pageSize);
    }
    
    // 更新用户
    public boolean updateUser(String id, String name, String email, Integer age) {
        try {
            ObjectId objectId = new ObjectId(id);
            
            // 验证输入
            if (name != null && name.trim().isEmpty()) {
                throw new IllegalArgumentException("Name cannot be empty");
            }
            
            if (email != null && !isValidEmail(email)) {
                throw new IllegalArgumentException("Invalid email format");
            }
            
            if (age != null && (age < 0 || age > 150)) {
                throw new IllegalArgumentException("Age must be between 0 and 150");
            }
            
            // 检查用户是否存在
            User existingUser = userDAO.findById(objectId);
            if (existingUser == null) {
                throw new IllegalArgumentException("User not found");
            }
            
            // 如果更新邮箱,检查新邮箱是否已被其他用户使用
            if (email != null && !email.equals(existingUser.getEmail())) {
                User userWithEmail = userDAO.findByEmail(email);
                if (userWithEmail != null && !userWithEmail.getId().equals(objectId)) {
                    throw new IllegalArgumentException("Email already exists");
                }
            }
            
            // 更新用户信息
            if (name != null) existingUser.setName(name);
            if (email != null) existingUser.setEmail(email);
            if (age != null) existingUser.setAge(age);
            
            return userDAO.updateUser(objectId, existingUser);
            
        } catch (IllegalArgumentException e) {
            throw new IllegalArgumentException("Invalid user ID format");
        }
    }
    
    public boolean updateUserAge(String id, int newAge) {
        try {
            ObjectId objectId = new ObjectId(id);
            
            if (newAge < 0 || newAge > 150) {
                throw new IllegalArgumentException("Age must be between 0 and 150");
            }
            
            return userDAO.updateAge(objectId, newAge);
            
        } catch (IllegalArgumentException e) {
            throw new IllegalArgumentException("Invalid user ID format");
        }
    }
    
    // 删除用户
    public boolean deleteUser(String id) {
        try {
            ObjectId objectId = new ObjectId(id);
            
            // 检查用户是否存在
            User existingUser = userDAO.findById(objectId);
            if (existingUser == null) {
                throw new IllegalArgumentException("User not found");
            }
            
            return userDAO.deleteUser(objectId);
            
        } catch (IllegalArgumentException e) {
            throw new IllegalArgumentException("Invalid user ID format");
        }
    }
    
    // 统计操作
    public long getUserCount() {
        return userDAO.countUsers();
    }
    
    public long getAdultUserCount() {
        return userDAO.countUsersByAge(18);
    }
    
    // 批量操作
    public List<ObjectId> createUsers(List<User> users) {
        // 验证所有用户数据
        for (User user : users) {
            if (user.getName() == null || user.getName().trim().isEmpty()) {
                throw new IllegalArgumentException("All users must have a name");
            }
            if (user.getEmail() == null || !isValidEmail(user.getEmail())) {
                throw new IllegalArgumentException("All users must have a valid email");
            }
        }
        
        return userDAO.createUsers(users);
    }
    
    public long bulkDeleteUsersByAge(int maxAge) {
        if (maxAge < 0) {
            throw new IllegalArgumentException("Age must be non-negative");
        }
        return userDAO.deleteUsersByAge(maxAge);
    }
    
    // 邮箱格式验证
    private boolean isValidEmail(String email) {
        return email != null && email.matches("^[A-Za-z0-9+_.-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}$");
    }
}

8. 高级查询操作

8.1 复杂查询实现

package com.example.dao;

import com.mongodb.client.MongoCollection;
import com.mongodb.client.model.*;
import org.bson.Document;
import org.bson.conversions.Bson;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.regex.Pattern;

public class AdvancedQueryDAO {
    
    private final MongoCollection<Document> collection;
    
    public AdvancedQueryDAO(MongoCollection<Document> collection) {
        this.collection = collection;
    }
    
    // 复合条件查询
    public List<Document> findUsersWithComplexConditions() {
        List<Document> results = new ArrayList<>();
        
        // 年龄在20-40之间,且名字包含"John"或邮箱以"gmail"结尾
        Bson ageFilter = Filters.and(
            Filters.gte("age", 20),
            Filters.lte("age", 40)
        );
        
        Bson nameOrEmailFilter = Filters.or(
            Filters.regex("name", ".*John.*", "i"),
            Filters.regex("email", ".*@gmail\\.com$", "i")
        );
        
        Bson complexFilter = Filters.and(ageFilter, nameOrEmailFilter);
        
        for (Document doc : collection.find(complexFilter)) {
            results.add(doc);
        }
        
        return results;
    }
    
    // 数组查询
    public List<Document> findUsersByTags(String... tags) {
        List<Document> results = new ArrayList<>();
        
        // 包含所有指定标签的用户
        Bson filter = Filters.all("tags", Arrays.asList(tags));
        
        for (Document doc : collection.find(filter)) {
            results.add(doc);
        }
        
        return results;
    }
    
    public List<Document> findUsersByAnyTag(String... tags) {
        List<Document> results = new ArrayList<>();
        
        // 包含任意一个指定标签的用户
        Bson filter = Filters.in("tags", Arrays.asList(tags));
        
        for (Document doc : collection.find(filter)) {
            results.add(doc);
        }
        
        return results;
    }
    
    // 嵌套文档查询
    public List<Document> findUsersByCity(String city) {
        List<Document> results = new ArrayList<>();
        
        Bson filter = Filters.eq("address.city", city);
        
        for (Document doc : collection.find(filter)) {
            results.add(doc);
        }
        
        return results;
    }
    
    // 存在性查询
    public List<Document> findUsersWithAddress() {
        List<Document> results = new ArrayList<>();
        
        Bson filter = Filters.exists("address");
        
        for (Document doc : collection.find(filter)) {
            results.add(doc);
        }
        
        return results;
    }
    
    public List<Document> findUsersWithoutTags() {
        List<Document> results = new ArrayList<>();
        
        Bson filter = Filters.or(
            Filters.exists("tags", false),
            Filters.size("tags", 0)
        );
        
        for (Document doc : collection.find(filter)) {
            results.add(doc);
        }
        
        return results;
    }
    
    // 正则表达式查询
    public List<Document> findUsersByEmailDomain(String domain) {
        List<Document> results = new ArrayList<>();
        
        Pattern pattern = Pattern.compile(".*@" + Pattern.quote(domain) + "$", Pattern.CASE_INSENSITIVE);
        Bson filter = Filters.regex("email", pattern);
        
        for (Document doc : collection.find(filter)) {
            results.add(doc);
        }
        
        return results;
    }
    
    // 类型查询
    public List<Document> findUsersWithStringAge() {
        List<Document> results = new ArrayList<>();
        
        Bson filter = Filters.type("age", "string");
        
        for (Document doc : collection.find(filter)) {
            results.add(doc);
        }
        
        return results;
    }
    
    // 地理位置查询(需要创建地理索引)
    public List<Document> findUsersNearLocation(double longitude, double latitude, double maxDistance) {
        List<Document> results = new ArrayList<>();
        
        Bson filter = Filters.near("location", longitude, latitude, maxDistance, null);
        
        for (Document doc : collection.find(filter)) {
            results.add(doc);
        }
        
        return results;
    }
    
    // 排序和限制
    public List<Document> findTopUsersByAge(int limit) {
        List<Document> results = new ArrayList<>();
        
        for (Document doc : collection.find()
                .sort(Sorts.descending("age"))
                .limit(limit)) {
            results.add(doc);
        }
        
        return results;
    }
    
    // 多字段排序
    public List<Document> findUsersOrderedByAgeAndName() {
        List<Document> results = new ArrayList<>();
        
        Bson sort = Sorts.orderBy(
            Sorts.ascending("age"),
            Sorts.ascending("name")
        );
        
        for (Document doc : collection.find().sort(sort)) {
            results.add(doc);
        }
        
        return results;
    }
}

9. 索引操作

9.1 索引管理类

package com.example.index;

import com.mongodb.client.MongoCollection;
import com.mongodb.client.model.IndexOptions;
import com.mongodb.client.model.Indexes;
import org.bson.Document;

import java.util.concurrent.TimeUnit;

public class IndexManager {
    
    private final MongoCollection<Document> collection;
    
    public IndexManager(MongoCollection<Document> collection) {
        this.collection = collection;
    }
    
    // 创建单字段索引
    public void createSingleFieldIndex() {
        // 在 email 字段上创建升序索引
        collection.createIndex(Indexes.ascending("email"));
        System.out.println("Created ascending index on email field");
        
        // 在 age 字段上创建降序索引
        collection.createIndex(Indexes.descending("age"));
        System.out.println("Created descending index on age field");
    }
    
    // 创建唯一索引
    public void createUniqueIndex() {
        IndexOptions indexOptions = new IndexOptions().unique(true);
        collection.createIndex(Indexes.ascending("email"), indexOptions);
        System.out.println("Created unique index on email field");
    }
    
    // 创建复合索引
    public void createCompoundIndex() {
        collection.createIndex(Indexes.compoundIndex(
            Indexes.ascending("age"),
            Indexes.descending("createdAt")
        ));
        System.out.println("Created compound index on age (asc) and createdAt (desc)");
    }
    
    // 创建文本索引
    public void createTextIndex() {
        collection.createIndex(Indexes.compoundIndex(
            Indexes.text("name"),
            Indexes.text("email")
        ));
        System.out.println("Created text index on name and email fields");
    }
    
    // 创建部分索引
    public void createPartialIndex() {
        IndexOptions indexOptions = new IndexOptions()
            .partialFilterExpression(new Document("age", new Document("$gte", 18)));
        
        collection.createIndex(Indexes.ascending("email"), indexOptions);
        System.out.println("Created partial index on email for users >= 18 years old");
    }
    
    // 创建 TTL 索引(生存时间索引)
    public void createTTLIndex() {
        IndexOptions indexOptions = new IndexOptions()
            .expireAfter(30L, TimeUnit.DAYS);
        
        collection.createIndex(Indexes.ascending("createdAt"), indexOptions);
        System.out.println("Created TTL index on createdAt field (30 days)");
    }
    
    // 创建稀疏索引
    public void createSparseIndex() {
        IndexOptions indexOptions = new IndexOptions().sparse(true);
        collection.createIndex(Indexes.ascending("phoneNumber"), indexOptions);
        System.out.println("Created sparse index on phoneNumber field");
    }
    
    // 创建地理空间索引
    public void createGeospatialIndex() {
        collection.createIndex(Indexes.geo2dsphere("location"));
        System.out.println("Created 2dsphere index on location field");
    }
    
    // 创建哈希索引
    public void createHashedIndex() {
        collection.createIndex(Indexes.hashed("userId"));
        System.out.println("Created hashed index on userId field");
    }
    
    // 列出所有索引
    public void listAllIndexes() {
        System.out.println("Existing indexes:");
        for (Document index : collection.listIndexes()) {
            System.out.println(index.toJson());
        }
    }
    
    // 删除索引
    public void dropIndexes() {
        // 删除特定索引
        collection.dropIndex("email_1");
        System.out.println("Dropped index on email field");
        
        // 删除所有索引(除了 _id 索引)
        // collection.dropIndexes();
    }
    
    // 获取索引统计信息
    public void getIndexStats() {
        // 这需要通过聚合管道来获取
        System.out.println("Index statistics would be retrieved through aggregation pipeline");
    }
}

10. 聚合管道

10.1 聚合操作实现

package com.example.aggregation;

import com.mongodb.client.MongoCollection;
import com.mongodb.client.AggregateIterable;
import com.mongodb.client.model.Aggregates;
import com.mongodb.client.model.Filters;
import com.mongodb.client.model.Sorts;
import org.bson.Document;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class AggregationOperations {
    
    private final MongoCollection<Document> collection;
    
    public AggregationOperations(MongoCollection<Document> collection) {
        this.collection = collection;
    }
    
    // 基本统计聚合
    public Document getUserStatistics() {
        List<Document> pipeline = Arrays.asList(
            new Document("$group", new Document("_id", null)
                .append("totalUsers", new Document("$sum", 1))
                .append("averageAge", new Document("$avg", "$age"))
                .append("minAge", new Document("$min", "$age"))
                .append("maxAge", new Document("$max", "$age"))
                .append("totalAge", new Document("$sum", "$age"))
            )
        );
        
        AggregateIterable<Document> result = collection.aggregate(pipeline);
        return result.first();
    }
    
    // 按年龄分组统计
    public List<Document> getUsersByAgeGroup() {
        List<Document> results = new ArrayList<>();
        
        List<Document> pipeline = Arrays.asList(
            new Document("$group", new Document("_id", 
                new Document("$switch", new Document("branches", Arrays.asList(
                    new Document("case", new Document("$lt", Arrays.asList("$age", 18)))
                        .append("then", "未成年"),
                    new Document("case", new Document("$lt", Arrays.asList("$age", 35)))
                        .append("then", "青年"),
                    new Document("case", new Document("$lt", Arrays.asList("$age", 60)))
                        .append("then", "中年")
                )).append("default", "老年"))
            ).append("count", new Document("$sum", 1))
             .append("averageAge", new Document("$avg", "$age"))),
            new Document("$sort", new Document("count", -1))
        );
        
        for (Document doc : collection.aggregate(pipeline)) {
            results.add(doc);
        }
        
        return results;
    }
    
    // 按城市分组统计
    public List<Document> getUsersByCity() {
        List<Document> results = new ArrayList<>();
        
        List<Document> pipeline = Arrays.asList(
            new Document("$match", new Document("address.city", new Document("$exists", true))),
            new Document("$group", new Document("_id", "$address.city")
                .append("userCount", new Document("$sum", 1))
                .append("averageAge", new Document("$avg", "$age"))
                .append("users", new Document("$push", new Document("name", "$name").append("email", "$email")))
            ),
            new Document("$sort", new Document("userCount", -1))
        );
        
        for (Document doc : collection.aggregate(pipeline)) {
            results.add(doc);
        }
        
        return results;
    }
    
    // 投影操作 - 重构输出格式
    public List<Document> getUserProfiles() {
        List<Document> results = new ArrayList<>();
        
        List<Document> pipeline = Arrays.asList(
            new Document("$project", new Document("_id", 0)
                .append("fullName", "$name")
                .append("contactInfo", new Document("email", "$email")
                    .append("phone", "$phoneNumber"))
                .append("demographics", new Document("age", "$age")
                    .append("ageGroup", new Document("$switch", new Document("branches", Arrays.asList(
                        new Document("case", new Document("$lt", Arrays.asList("$age", 25)))
                            .append("then", "Young"),
                        new Document("case", new Document("$lt", Arrays.asList("$age", 50)))
                            .append("then", "Middle-aged")
                    )).append("default", "Senior"))))
                .append("location", "$address.city")
                .append("isActive", new Document("$cond", Arrays.asList(
                    new Document("$ne", Arrays.asList("$lastLoginDate", null)),
                    true,
                    false
                )))
            )
        );
        
        for (Document doc : collection.aggregate(pipeline)) {
            results.add(doc);
        }
        
        return results;
    }
    
    // 查找操作 - 关联其他集合
    public List<Document> getUsersWithOrderInfo(MongoCollection<Document> ordersCollection) {
        List<Document> results = new ArrayList<>();
        
        List<Document> pipeline = Arrays.asList(
            new Document("$lookup", new Document("from", "orders")
                .append("localField", "_id")
                .append("foreignField", "userId")
                .append("as", "orders")
            ),
            new Document("$addFields", new Document("orderCount", new Document("$size", "$orders"))
                .append("totalOrderValue", new Document("$sum", "$orders.amount"))
            ),
            new Document("$match", new Document("orderCount", new Document("$gt", 0))),
            new Document("$sort", new Document("totalOrderValue", -1))
        );
        
        for (Document doc : collection.aggregate(pipeline)) {
            results.add(doc);
        }
        
        return results;
    }
    
    // 解构数组操作
    public List<Document> getUserTagAnalysis() {
        List<Document> results = new ArrayList<>();
        
        List<Document> pipeline = Arrays.asList(
            new Document("$match", new Document("tags", new Document("$exists", true))),
            new Document("$unwind", "$tags"),
            new Document("$group", new Document("_id", "$tags")
                .append("userCount", new Document("$sum", 1))
                .append("users", new Document("$push", "$name"))
            ),
            new Document("$sort", new Document("userCount", -1)),
            new Document("$limit", 10)
        );
        
        for (Document doc : collection.aggregate(pipeline)) {
            results.add(doc);
        }
        
        return results;
    }
    
    // 时间序列分析
    public List<Document> getUserRegistrationTrend() {
        List<Document> results = new ArrayList<>();
        
        List<Document> pipeline = Arrays.asList(
            new Document("$group", new Document("_id", new Document("year", new Document("$year", "$createdAt"))
                .append("month", new Document("$month", "$createdAt")))
                .append("registrations", new Document("$sum", 1))
                .append("averageAge", new Document("$avg", "$age"))
            ),
            new Document("$sort", new Document("_id.year", 1).append("_id.month", 1)),
            new Document("$project", new Document("_id", 0)
                .append("period", new Document("$concat", Arrays.asList(
                    new Document("$toString", "$_id.year"),
                    "-",
                    new Document("$toString", "$_id.month")
                )))
                .append("registrations", 1)
                .append("averageAge", new Document("$round", Arrays.asList("$averageAge", 1)))
            )
        );
        
        for (Document doc : collection.aggregate(pipeline)) {
            results.add(doc);
        }
        
        return results;
    }
    
    // 复杂的多阶段聚合
    public List<Document> getAdvancedUserAnalytics() {
        List<Document> results = new ArrayList<>();
        
        List<Document> pipeline = Arrays.asList(
            // 阶段 1: 匹配活跃用户
            new Document("$match", new Document("isActive", true)),
            
            // 阶段 2: 添加计算字段
            new Document("$addFields", new Document("ageGroup", 
                new Document("$switch", new Document("branches", Arrays.asList(
                    new Document("case", new Document("$lt", Arrays.asList("$age", 25)))
                        .append("then", "18-24"),
                    new Document("case", new Document("$lt", Arrays.asList("$age", 35)))
                        .append("then", "25-34"),
                    new Document("case", new Document("$lt", Arrays.asList("$age", 50)))
                        .append("then", "35-49")
                )).append("default", "50+"))
            ).append("emailDomain", new Document("$arrayElemAt", Arrays.asList(
                new Document("$split", Arrays.asList("$email", "@")), 1
            )))),
            
            // 阶段 3: 按年龄组和邮箱域名分组
            new Document("$group", new Document("_id", new Document("ageGroup", "$ageGroup")
                .append("emailDomain", "$emailDomain"))
                .append("userCount", new Document("$sum", 1))
                .append("names", new Document("$push", "$name"))
            ),
            
            // 阶段 4: 重新分组以获得每个年龄组的信息
            new Document("$group", new Document("_id", "$_id.ageGroup")
                .append("totalUsers", new Document("$sum", "$userCount"))
                .append("domains", new Document("$push", new Document("domain", "$_id.emailDomain")
                    .append("count", "$userCount")))
            ),
            
            // 阶段 5: 排序
            new Document("$sort", new Document("totalUsers", -1)),
            
            // 阶段 6: 投影最终结果
            new Document("$project", new Document("_id", 0)
                .append("ageGroup", "$_id")
                .append("totalUsers", 1)
                .append("topDomains", new Document("$slice", Arrays.asList(
                    new Document("$sortArray", new Document("input", "$domains")
                        .append("sortBy", new Document("count", -1))), 3
                )))
            )
        );
        
        for (Document doc : collection.aggregate(pipeline)) {
            results.add(doc);
        }
        
        return results;
    }
}

11. 事务处理

11.1 事务操作实现

package com.example.transaction;

import com.mongodb.client.ClientSession;
import com.mongodb.client.MongoClient;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoDatabase;
import com.mongodb.client.model.Filters;
import com.mongodb.client.model.Updates;
import org.bson.Document;
import org.bson.types.ObjectId;

public class TransactionManager {
    
    private final MongoClient mongoClient;
    private final MongoDatabase database;
    
    public TransactionManager(MongoClient mongoClient, MongoDatabase database) {
        this.mongoClient = mongoClient;
        this.database = database;
    }
    
    // 简单事务示例:转账操作
    public boolean transferMoney(ObjectId fromUserId, ObjectId toUserId, double amount) {
        ClientSession session = mongoClient.startSession();
        
        try {
            return session.withTransaction(() -> {
                MongoCollection<Document> accounts = database.getCollection("accounts");
                
                // 检查转出账户余额
                Document fromAccount = accounts.find(session, Filters.eq("_id", fromUserId)).first();
                if (fromAccount == null) {
                    throw new RuntimeException("转出账户不存在");
                }
                
                double fromBalance = fromAccount.getDouble("balance");
                if (fromBalance < amount) {
                    throw new RuntimeException("余额不足");
                }
                
                // 检查转入账户是否存在
                Document toAccount = accounts.find(session, Filters.eq("_id", toUserId)).first();
                if (toAccount == null) {
                    throw new RuntimeException("转入账户不存在");
                }
                
                // 执行转账
                accounts.updateOne(session, 
                    Filters.eq("_id", fromUserId),
                    Updates.inc("balance", -amount)
                );
                
                accounts.updateOne(session,
                    Filters.eq("_id", toUserId),
                    Updates.inc("balance", amount)
                );
                
                // 记录交易日志
                MongoCollection<Document> transactions = database.getCollection("transactions");
                Document transaction = new Document()
                    .append("fromUserId", fromUserId)
                    .append("toUserId", toUserId)
                    .append("amount", amount)
                    .append("timestamp", System.currentTimeMillis())
                    .append("status", "completed");
                
                transactions.insertOne(session, transaction);
                
                return true;
            });
            
        } catch (Exception e) {
            System.err.println("转账失败: " + e.getMessage());
            return false;
        } finally {
            session.close();
        }
    }
    
    // 复杂事务示例:创建订单
    public ObjectId createOrderWithInventoryUpdate(ObjectId userId, String productId, int quantity) {
        ClientSession session = mongoClient.startSession();
        
        try {
            return session.withTransaction(() -> {
                MongoCollection<Document> users = database.getCollection("users");
                MongoCollection<Document> products = database.getCollection("products");
                MongoCollection<Document> orders = database.getCollection("orders");
                MongoCollection<Document> inventory = database.getCollection("inventory");
                
                // 1. 验证用户存在
                Document user = users.find(session, Filters.eq("_id", userId)).first();
                if (user == null) {
                    throw new RuntimeException("用户不存在");
                }
                
                // 2. 验证产品存在并获取价格
                Document product = products.find(session, Filters.eq("productId", productId)).first();
                if (product == null) {
                    throw new RuntimeException("产品不存在");
                }
                
                double price = product.getDouble("price");
                
                // 3. 检查库存并更新
                Document inventoryDoc = inventory.find(session, Filters.eq("productId", productId)).first();
                if (inventoryDoc == null) {
                    throw new RuntimeException("库存记录不存在");
                }
                
                int currentStock = inventoryDoc.getInteger("quantity");
                if (currentStock < quantity) {
                    throw new RuntimeException("库存不足");
                }
                
                // 更新库存
                inventory.updateOne(session,
                    Filters.eq("productId", productId),
                    Updates.inc("quantity", -quantity)
                );
                
                // 4. 创建订单
                ObjectId orderId = new ObjectId();
                Document order = new Document()
                    .append("_id", orderId)
                    .append("userId", userId)
                    .append("productId", productId)
                    .append("quantity", quantity)
                    .append("unitPrice", price)
                    .append("totalAmount", price * quantity)
                    .append("status", "pending")
                    .append("createdAt", System.currentTimeMillis());
                
                orders.insertOne(session, order);
                
                // 5. 更新用户订单历史
                users.updateOne(session,
                    Filters.eq("_id", userId),
                    Updates.push("orderHistory", orderId)
                );
                
                return orderId;
            });
            
        } catch (Exception e) {
            System.err.println("创建订单失败: " + e.getMessage());
            return null;
        } finally {
            session.close();
        }
    }
    
    // 回调式事务处理
    public boolean performMultiCollectionOperation() {
        ClientSession session = mongoClient.startSession();
        
        try {
            session.withTransaction(() -> {
                MongoCollection<Document> collection1 = database.getCollection("collection1");
                MongoCollection<Document> collection2 = database.getCollection("collection2");
                
                // 在事务中执行多个操作
                collection1.insertOne(session, new Document("field1", "value1"));
                collection2.updateOne(session, 
                    Filters.eq("_id", "someId"),
                    Updates.set("field2", "value2")
                );
                
                // 如果这里抛出异常,整个事务会回滚
                // throw new RuntimeException("模拟失败");
                
                return "success";
            });
            
            return true;
            
        } catch (Exception e) {
            System.err.println("事务执行失败: " + e.getMessage());
            return false;
        } finally {
            session.close();
        }
    }
    
    // 手动事务控制
    public boolean manualTransactionControl() {
        ClientSession session = mongoClient.startSession();
        
        try {
            session.startTransaction();
            
            MongoCollection<Document> users = database.getCollection("users");
            MongoCollection<Document> logs = database.getCollection("logs");
            
            try {
                // 执行业务操作
                users.insertOne(session, new Document("name", "New User"));
                logs.insertOne(session, new Document("action", "user_created"));
                
                // 手动提交事务
                session.commitTransaction();
                return true;
                
            } catch (Exception e) {
                // 手动回滚事务
                session.abortTransaction();
                System.err.println("事务回滚: " + e.getMessage());
                return false;
            }
            
        } finally {
            session.close();
        }
    }
}

12. Spring Boot 集成

12.1 Spring Boot 配置

// pom.xml 添加依赖
/*
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
*/

// application.yml
/*
spring:
  data:
    mongodb:
      uri: mongodb://localhost:27017/myapp
      # 或者分别配置
      host: localhost
      port: 27017
      database: myapp
      username: admin
      password: password
      authentication-database: admin
      
server:
  port: 8080
  
logging:
  level:
    org.springframework.data.mongodb: DEBUG
*/

package com.example.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.data.mongodb.config.AbstractMongoClientConfiguration;
import org.springframework.data.mongodb.repository.config.EnableMongoRepositories;

@Configuration
@EnableMongoRepositories(basePackages = "com.example.repository")
public class MongoConfig extends AbstractMongoClientConfiguration {
    
    @Override
    protected String getDatabaseName() {
        return "myapp";
    }
    
    // 自定义配置
    /*
    @Override
    public MongoClient mongoClient() {
        ConnectionString connectionString = new ConnectionString("mongodb://localhost:27017/myapp");
        MongoClientSettings mongoClientSettings = MongoClientSettings.builder()
            .applyConnectionString(connectionString)
            .build();
        return MongoClients.create(mongoClientSettings);
    }
    */
}

12.2 Spring Data MongoDB 实体类

package com.example.entity;

import org.springframework.data.annotation.Id;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.LastModifiedDate;
import org.springframework.data.mongodb.core.mapping.Document;
import org.springframework.data.mongodb.core.mapping.Field;
import org.springframework.data.mongodb.core.index.Indexed;

import java.time.LocalDateTime;
import java.util.List;

@Document(collection = "users")
public class User {
    
    @Id
    private String id;
    
    @Field("full_name")
    private String name;
    
    @Indexed(unique = true)
    private String email;
    
    private Integer age;
    
    private Address address;
    
    private List<String> tags;
    
    @CreatedDate
    private LocalDateTime createdAt;
    
    @LastModifiedDate
    private LocalDateTime updatedAt;
    
    // 构造函数
    public User() {}
    
    public User(String name, String email, Integer age) {
        this.name = name;
        this.email = email;
        this.age = age;
    }
    
    // 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 String getEmail() { return email; }
    public void setEmail(String email) { this.email = email; }
    
    public Integer getAge() { return age; }
    public void setAge(Integer age) { this.age = age; }
    
    public Address getAddress() { return address; }
    public void setAddress(Address address) { this.address = address; }
    
    public List<String> getTags() { return tags; }
    public void setTags(List<String> tags) { this.tags = tags; }
    
    public LocalDateTime getCreatedAt() { return createdAt; }
    public void setCreatedAt(LocalDateTime createdAt) { this.createdAt = createdAt; }
    
    public LocalDateTime getUpdatedAt() { return updatedAt; }
    public void setUpdatedAt(LocalDateTime updatedAt) { this.updatedAt = updatedAt; }
}

@Document
class Address {
    private String street;
    private String city;
    private String zipcode;
    private String country;
    
    // 构造函数和 Getter/Setter 方法
    public Address() {}
    
    public Address(String street, String city, String zipcode, String country) {
        this.street = street;
        this.city = city;
        this.zipcode = zipcode;
        this.country = country;
    }
    
    // Getter 和 Setter 方法省略...
}

12.3 Spring Data MongoDB Repository

package com.example.repository;

import com.example.entity.User;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.mongodb.repository.MongoRepository;
import org.springframework.data.mongodb.repository.Query;
import org.springframework.data.mongodb.repository.Aggregation;
import org.springframework.stereotype.Repository;

import java.util.List;
import java.util.Optional;

@Repository
public interface UserRepository extends MongoRepository<User, String> {
    
    // 基本查询方法(Spring Data 自动实现)
    Optional<User> findByEmail(String email);
    
    List<User> findByName(String name);
    
    List<User> findByAgeGreaterThan(Integer age);
    
    List<User> findByAgeBetween(Integer minAge, Integer maxAge);
    
    List<User> findByNameContainingIgnoreCase(String keyword);
    
    List<User> findByAddressCity(String city);
    
    List<User> findByTagsContaining(String tag);
    
    // 分页查询
    Page<User> findByAgeGreaterThan(Integer age, Pageable pageable);
    
    // 排序查询
    List<User> findByOrderByAgeDesc();
    
    List<User> findByAgeBetweenOrderByNameAsc(Integer minAge, Integer maxAge);
    
    // 自定义查询
    @Query("{ 'age' : { $gte: ?0, $lte: ?1 } }")
    List<User> findUsersInAgeRange(Integer minAge, Integer maxAge);
    
    @Query("{ 'email' : { $regex: ?0, $options: 'i' } }")
    List<User> findByEmailPattern(String pattern);
    
    @Query(value = "{ 'age' : { $gte: ?0 } }", fields = "{ 'name' : 1, 'email' : 1 }")
    List<User> findUserNamesAndEmailsByMinAge(Integer minAge);
    
    // 删除查询
    Long deleteByAge(Integer age);
    
    Long deleteByAgeGreaterThan(Integer age);
    
    // 聚合查询
    @Aggregation(pipeline = {
        "{ $group: { _id: null, totalUsers: { $sum: 1 }, averageAge: { $avg: '$age' } } }"
    })
    UserStatistics getUserStatistics();
    
    @Aggregation(pipeline = {
        "{ $group: { _id: '$address.city', count: { $sum: 1 } } }",
        "{ $sort: { count: -1 } }"
    })
    List<CityUserCount> getUserCountByCity();
    
    // 统计接口
    interface UserStatistics {
        Integer getTotalUsers();
        Double getAverageAge();
    }
    
    interface CityUserCount {
        String getId(); // city name
        Integer getCount();
    }
}

12.4 Service 层(Spring Boot)

package com.example.service;

import com.example.entity.User;
import com.example.repository.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.Optional;

@Service
@Transactional
public class UserService {
    
    @Autowired
    private UserRepository userRepository;
    
    // 创建用户
    public User createUser(User user) {
        // 业务逻辑验证
        validateUser(user);
        
        // 检查邮箱是否已存在
        Optional<User> existingUser = userRepository.findByEmail(user.getEmail());
        if (existingUser.isPresent()) {
            throw new IllegalArgumentException("Email already exists");
        }
        
        return userRepository.save(user);
    }
    
    // 批量创建用户
    public List<User> createUsers(List<User> users) {
        // 验证所有用户
        users.forEach(this::validateUser);
        
        return userRepository.saveAll(users);
    }
    
    // 获取用户
    public Optional<User> getUserById(String id) {
        return userRepository.findById(id);
    }
    
    public Optional<User> getUserByEmail(String email) {
        return userRepository.findByEmail(email);
    }
    
    public List<User> getAllUsers() {
        return userRepository.findAll();
    }
    
    // 分页查询
    public Page<User> getUsersWithPagination(int page, int size, String sortBy, String sortDir) {
        Sort sort = sortDir.equalsIgnoreCase("desc") ? 
            Sort.by(sortBy).descending() : Sort.by(sortBy).ascending();
        
        Pageable pageable = PageRequest.of(page, size, sort);
        return userRepository.findAll(pageable);
    }
    
    // 条件查询
    public List<User> getUsersByAgeRange(Integer minAge, Integer maxAge) {
        return userRepository.findByAgeBetween(minAge, maxAge);
    }
    
    public List<User> searchUsersByName(String keyword) {
        return userRepository.findByNameContainingIgnoreCase(keyword);
    }
    
    public List<User> getUsersByCity(String city) {
        return userRepository.findByAddressCity(city);
    }
    
    public List<User> getUsersByTag(String tag) {
        return userRepository.findByTagsContaining(tag);
    }
    
    // 更新用户
    public User updateUser(String id, User updatedUser) {
        return userRepository.findById(id)
            .map(existingUser -> {
                existingUser.setName(updatedUser.getName());
                existingUser.setEmail(updatedUser.getEmail());
                existingUser.setAge(updatedUser.getAge());
                existingUser.setAddress(updatedUser.getAddress());
                existingUser.setTags(updatedUser.getTags());
                return userRepository.save(existingUser);
            })
            .orElseThrow(() -> new IllegalArgumentException("User not found with id: " + id));
    }
    
    // 删除用户
    public boolean deleteUser(String id) {
        return userRepository.findById(id)
            .map(user -> {
                userRepository.delete(user);
                return true;
            })
            .orElse(false);
    }
    
    public void deleteAllUsers() {
        userRepository.deleteAll();
    }
    
    // 统计操作
    public long getUserCount() {
        return userRepository.count();
    }
    
    public UserRepository.UserStatistics getUserStatistics() {
        return userRepository.getUserStatistics();
    }
    
    public List<UserRepository.CityUserCount> getUserCountByCity() {
        return userRepository.getUserCountByCity();
    }
    
    // 业务逻辑验证
    private void validateUser(User user) {
        if (user.getName() == null || user.getName().trim().isEmpty()) {
            throw new IllegalArgumentException("Name cannot be empty");
        }
        
        if (user.getEmail() == null || !isValidEmail(user.getEmail())) {
            throw new IllegalArgumentException("Invalid email format");
        }
        
        if (user.getAge() != null && (user.getAge() < 0 || user.getAge() > 150)) {
            throw new IllegalArgumentException("Age must be between 0 and 150");
        }
    }
    
    private boolean isValidEmail(String email) {
        return email.matches("^[A-Za-z0-9+_.-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}$");
    }
}

12.5 Controller 层

package com.example.controller;

import com.example.entity.User;
import com.example.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import javax.validation.Valid;
import java.util.List;
import java.util.Optional;

@RestController
@RequestMapping("/api/users")
@CrossOrigin(origins = "*")
public class UserController {
    
    @Autowired
    private UserService userService;
    
    // 创建用户
    @PostMapping
    public ResponseEntity<User> createUser(@Valid @RequestBody User user) {
        try {
            User createdUser = userService.createUser(user);
            return new ResponseEntity<>(createdUser, HttpStatus.CREATED);
        } catch (IllegalArgumentException e) {
            return new ResponseEntity<>(null, HttpStatus.BAD_REQUEST);
        }
    }
    
    // 批量创建用户
    @PostMapping("/batch")
    public ResponseEntity<List<User>> createUsers(@Valid @RequestBody List<User> users) {
        try {
            List<User> createdUsers = userService.createUsers(users);
            return new ResponseEntity<>(createdUsers, HttpStatus.CREATED);
        } catch (IllegalArgumentException e) {
            return new ResponseEntity<>(null, HttpStatus.BAD_REQUEST);
        }
    }
    
    // 获取所有用户
    @GetMapping
    public ResponseEntity<List<User>> getAllUsers() {
        List<User> users = userService.getAllUsers();
        return new ResponseEntity<>(users, HttpStatus.OK);
    }
    
    // 分页获取用户
    @GetMapping("/page")
    public ResponseEntity<Page<User>> getUsersWithPagination(
            @RequestParam(defaultValue = "0") int page,
            @RequestParam(defaultValue = "10") int size,
            @RequestParam(defaultValue = "id") String sortBy,
            @RequestParam(defaultValue = "asc") String sortDir) {
        
        Page<User> users = userService.getUsersWithPagination(page, size, sortBy, sortDir);
        return new ResponseEntity<>(users, HttpStatus.OK);
    }
    
    // 根据ID获取用户
    @GetMapping("/{id}")
    public ResponseEntity<User> getUserById(@PathVariable String id) {
        Optional<User> user = userService.getUserById(id);
        return user.map(u -> new ResponseEntity<>(u, HttpStatus.OK))
                  .orElseGet(() -> new ResponseEntity<>(HttpStatus.NOT_FOUND));
    }
    
    // 根据邮箱获取用户
    @GetMapping("/email/{email}")
    public ResponseEntity<User> getUserByEmail(@PathVariable String email) {
        Optional<User> user = userService.getUserByEmail(email);
        return user.map(u -> new ResponseEntity<>(u, HttpStatus.OK))
                  .orElseGet(() -> new ResponseEntity<>(HttpStatus.NOT_FOUND));
    }
    
    // 条件查询
    @GetMapping("/age-range")
    public ResponseEntity<List<User>> getUsersByAgeRange(
            @RequestParam Integer minAge,
            @RequestParam Integer maxAge) {
        List<User> users = userService.getUsersByAgeRange(minAge, maxAge);
        return new ResponseEntity<>(users, HttpStatus.OK);
    }
    
    @GetMapping("/search")
    public ResponseEntity<List<User>> searchUsers(@RequestParam String keyword) {
        List<User> users = userService.searchUsersByName(keyword);
        return new ResponseEntity<>(users, HttpStatus.OK);
    }
    
    @GetMapping("/city/{city}")
    public ResponseEntity<List<User>> getUsersByCity(@PathVariable String city) {
        List<User> users = userService.getUsersByCity(city);
        return new ResponseEntity<>(users, HttpStatus.OK);
    }
    
    @GetMapping("/tag/{tag}")
    public ResponseEntity<List<User>> getUsersByTag(@PathVariable String tag) {
        List<User> users = userService.getUsersByTag(tag);
        return new ResponseEntity<>(users, HttpStatus.OK);
    }
    
    // 更新用户
    @PutMapping("/{id}")
    public ResponseEntity<User> updateUser(@PathVariable String id, @Valid @RequestBody User user) {
        try {
            User updatedUser = userService.updateUser(id, user);
            return new ResponseEntity<>(updatedUser, HttpStatus.OK);
        } catch (IllegalArgumentException e) {
            return new ResponseEntity<>(null, HttpStatus.NOT_FOUND);
        }
    }
    
    // 删除用户
    @DeleteMapping("/{id}")
    public ResponseEntity<Void> deleteUser(@PathVariable String id) {
        boolean deleted = userService.deleteUser(id);
        return deleted ? 
            new ResponseEntity<>(HttpStatus.NO_CONTENT) : 
            new ResponseEntity<>(HttpStatus.NOT_FOUND);
    }
    
    // 统计信息
    @GetMapping("/count")
    public ResponseEntity<Long> getUserCount() {
        long count = userService.getUserCount();
        return new ResponseEntity<>(count, HttpStatus.OK);
    }
    
    @GetMapping("/statistics")
    public ResponseEntity<UserService.UserRepository.UserStatistics> getUserStatistics() {
        UserService.UserRepository.UserStatistics stats = userService.getUserStatistics();
        return new ResponseEntity<>(stats, HttpStatus.OK);
    }
    
    @GetMapping("/city-stats")
    public ResponseEntity<List<UserService.UserRepository.CityUserCount>> getCityStats() {
        List<UserService.UserRepository.CityUserCount> stats = userService.getUserCountByCity();
        return new ResponseEntity<>(stats, HttpStatus.OK);
    }
}

13. 最佳实践

13.1 性能优化

package com.example.optimization;

import com.mongodb.client.MongoCollection;
import com.mongodb.client.model.IndexOptions;
import com.mongodb.client.model.Indexes;
import org.bson.Document;

public class PerformanceOptimization {
    
    private final MongoCollection<Document> collection;
    
    public PerformanceOptimization(MongoCollection<Document> collection) {
        this.collection = collection;
    }
    
    // 1. 创建合适的索引
    public void createOptimizedIndexes() {
        // 单字段索引
        collection.createIndex(Indexes.ascending("email"));
        collection.createIndex(Indexes.ascending("age"));
        
        // 复合索引 - 注意字段顺序
        collection.createIndex(Indexes.compoundIndex(
            Indexes.ascending("age"),      // 选择性高的字段放前面
            Indexes.ascending("city"),
            Indexes.descending("createdAt")
        ));
        
        // 文本索引
        collection.createIndex(Indexes.text("name"));
        
        // 部分索引 - 只索引满足条件的文档
        IndexOptions partialOptions = new IndexOptions()
            .partialFilterExpression(new Document("age", new Document("$gte", 18)));
        collection.createIndex(Indexes.ascending("email"), partialOptions);
    }
    
    // 2. 查询优化示例
    public void optimizedQueries() {
        // 使用投影减少网络传输
        collection.find()
            .projection(new Document("name", 1).append("email", 1))
            .forEach(doc -> System.out.println(doc.toJson()));
        
        // 使用 limit 限制结果集
        collection.find()
            .limit(10)
            .forEach(doc -> System.out.println(doc.toJson()));
        
        // 使用 hint 强制使用特定索引
        collection.find(new Document("age", new Document("$gte", 18)))
            .hint(new Document("age", 1))
            .forEach(doc -> System.out.println(doc.toJson()));
    }
    
    // 3. 批量操作优化
    public void optimizedBulkOperations() {
        // 使用批量写入而不是多次单独写入
        // ... 批量操作代码
    }
}

13.2 错误处理和日志

package com.example.exception;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;

@ControllerAdvice
public class GlobalExceptionHandler {
    
    private static final Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class);
    
    @ExceptionHandler(IllegalArgumentException.class)
    public ResponseEntity<ErrorResponse> handleIllegalArgument(IllegalArgumentException e) {
        logger.warn("Invalid argument: {}", e.getMessage());
        return new ResponseEntity<>(
            new ErrorResponse("INVALID_ARGUMENT", e.getMessage()),
            HttpStatus.BAD_REQUEST
        );
    }
    
    @ExceptionHandler(RuntimeException.class)
    public ResponseEntity<ErrorResponse> handleRuntimeException(RuntimeException e) {
        logger.error("Runtime exception occurred", e);
        return new ResponseEntity<>(
            new ErrorResponse("INTERNAL_ERROR", "An internal error occurred"),
            HttpStatus.INTERNAL_SERVER_ERROR
        );
    }
    
    public static class ErrorResponse {
        private String code;
        private String message;
        
        public ErrorResponse(String code, String message) {
            this.code = code;
            this.message = message;
        }
        
        // Getter 方法
        public String getCode() { return code; }
        public String getMessage() { return message; }
    }
}

13.3 主应用程序类

package com.example;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.data.mongodb.config.EnableMongoAuditing;

@SpringBootApplication
@EnableMongoAuditing
public class MongoDBApplication {
    
    public static void main(String[] args) {
        SpringApplication.run(MongoDBApplication.class, args);
        System.out.println("MongoDB Spring Boot Application Started!");
    }
}

13.4 测试类示例

package com.example;

import com.example.entity.User;
import com.example.service.UserService;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.TestPropertySource;

import static org.junit.jupiter.api.Assertions.*;

@SpringBootTest
@TestPropertySource(properties = {
    "spring.data.mongodb.database=test_db"
})
public class UserServiceTest {
    
    @Autowired
    private UserService userService;
    
    @Test
    public void testCreateUser() {
        User user = new User("Test User", "test@example.com", 25);
        User createdUser = userService.createUser(user);
        
        assertNotNull(createdUser.getId());
        assertEquals("Test User", createdUser.getName());
        assertEquals("test@example.com", createdUser.getEmail());
        assertEquals(25, createdUser.getAge());
    }
    
    @Test
    public void testFindUserByEmail() {
        // 先创建一个用户
        User user = new User("Find Test", "findtest@example.com", 30);
        userService.createUser(user);
        
        // 然后查找
        var foundUser = userService.getUserByEmail("findtest@example.com");
        assertTrue(foundUser.isPresent());
        assertEquals("Find Test", foundUser.get().getName());
    }
}

这个完整指南涵盖了 MongoDB 与 Java 集成的所有重要方面,从基础安装配置到高级的聚合操作和 Spring Boot 集成。每个部分都包含详细的代码示例和解释,可以作为开发过程中的参考手册。


网站公告

今日签到

点亮在社区的每一天
去签到