首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Java 操作 MongoDB:模糊查詢與分頁查詢完整實戰

     編輯:Java 相關知識

MongoDB Java 驅動基礎設置

<dependency>
    <groupId>org.mongodb</groupId>
    <artifactId>mongo-java-driver</artifactId>
    3.12.14 <!-- 3.x 系列,4.x+ API 不同 -->
</dependency>

連接配置最佳實踐

public class MongoConfig {
    public static MongoClient createClient() {
        // 種子節點列表 (生產環境至少 3 個)
        List seeds = Arrays.asList(
            new ServerAddress("192.168.1.10", 27017),
            new ServerAddress("192.168.1.11", 27017)
        );
        
        // 認證憑證
        List creds = Collections.singletonList(
            MongoCredential.createCredential("appUser", "myDB", "password".toCharArray())
        );
        
        // 連接池與超時調優
        MongoClientOptions options = MongoClientOptions.builder()
            .connectionsPerHost(100)           // 每主機最大連接數
            .threadsAllowedToBlockForConnectionMultiplier(50) // 等待線程倍數
            .maxWaitTime(120_000)              // 獲取連接最大等待 2分鐘
            .connectTimeout(10_000)            // 建立連接超時 10秒
            .socketTimeout(60_000)             // Socket 讀寫超時 60秒
            .build();
            
        return new MongoClient(seeds, creds, options);
    }
}

模糊查詢:正則表達式四大模式

MongoDB 使用 Pattern (java.util.regex) 實現類 SQL LIKE:

模式正則語法Java 代碼相當於 SQL
精確匹配^value$Pattern.compile("^name$", Pattern.CASE_INSENSITIVE)WHERE name = 'name'
前綴匹配 (右匹配)^prefix.*Pattern.compile("^name.*", Pattern.CASE_INSENSITIVE)WHERE name LIKE 'name%'
後綴匹配 (左匹配).*suffix$Pattern.compile("^.*name$", Pattern.CASE_INSENSITIVE)WHERE name LIKE '%name'
包含匹配 (模糊).*substr.*Pattern.compile("^.*name.*$", Pattern.CASE_INSENSITIVE)WHERE name LIKE '%name%'

完整查詢代碼

public List fuzzyQuery(MongoDatabase db, String collection, String field, String keyword, int limit) {
    // 1. 構建不區分大小寫的包含匹配正則
    Pattern pattern = Pattern.compile(".*" + Pattern.quote(keyword) + ".*", Pattern.CASE_INSENSITIVE);
    
    // 2. 查詢條件
    Bson filter = Filters.regex(field, pattern);
    
    // 3. 排序 (可選)
    Bson sort = Sorts.ascending(field); // 1=升序, -1=降序
    
    // 4. 執行查詢
    return db.getCollection(collection)
             .find(filter)
             .sort(sort)
             .limit(limit)
             .into(new ArrayList<>());
}

分頁查詢:skip + limit

public  List paginateQuery(MongoDatabase db, String collection, Bson filter, 
                                 Bson sort, int pageNum, int pageSize, Class clazz) {
    // 參數校驗
    if (pageNum < 1) pageNum = 1;
    if (pageSize < 1) pageSize = 20;
    if (pageSize > 100) pageSize = 100; // 防止過大
    
    long skip = (long)(pageNum - 1) * pageSize;
    
    return db.getCollection(collection)
             .find(filter)
             .sort(sort)
             .skip(skip)
             .limit(pageSize)
             .map(doc -> MongoUtils.fromDocument(doc, clazz)) // 自定義文檔轉對象
             .into(new ArrayList<>());
}

// 獲取總數 (用於前端分頁組件)
public long countTotal(MongoDatabase db, String collection, Bson filter) {
    return db.getCollection(collection).countDocuments(filter);
}

綜合實戰:用戶查詢服務

@Service
public class UserQueryService {
    private final MongoDatabase db;
    
    public UserQueryService(MongoClient client) {
        this.db = client.getDatabase("business_db");
    }
    
    public PageResult searchUsers(String keyword, int page, int size) {
        // 1. 構建過濾器
        Bson filter = Filters.and(
            Filters.eq("status", 1), // 只查啟用用戶
            keyword != null ? Filters.or(
                Filters.regex("username", Pattern.compile(".*" + Pattern.quote(keyword) + ".*", Pattern.CASE_INSENSITIVE)),
                Filters.regex("email", Pattern.compile(".*" + Pattern.quote(keyword) + ".*", Pattern.CASE_INSENSITIVE)),
                Filters.regex("phone", Pattern.compile(".*" + Pattern.quote(keyword) + ".*"))
            ) : new Document()
        );
        
        // 2. 總數
        long total = db.getCollection("users").countDocuments(filter);
        
        // 3. 分頁數據
        List data = paginateQuery(db, "users", filter, 
            Sorts.descending("createTime"), page, size, UserDTO.class);
        
        return new PageResult<>(page, size, total, data);
    }
}

性能優化關鍵點

  • 建立索引:模糊查詢字段 (username/email/phone) 必須建立文本索引或普通索引,否則全表掃描極慢。
    db.users.createIndex({username: "text", email: "text", phone: "text"}) (文本索引支援更豐富搜索)
  • 避免深分頁:skip(100000) 性能極差。大數據量請用游標分頁 (記住上一頁最後一個 _id,查詢 {_id: {$gt: lastId}})。
  • 投影字段:只查需要的字段 .projection(fields(include("username", "email"), excludeId())),減少網絡傳輸。
  • 連接池監控:監控 connectionsInUse、waitQueueSize,及時擴容。

避坑指南

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved
坑點後果解決
正則未用 Pattern.quote關鍵字含特殊字符 (.,*,?,+,...) 導致匹配錯誤或注入必須 Pattern.quote(keyword) 轉義
大小寫敏感漏查數據加 Pattern.CASE_INSENSITIVE 標誌
skip 過大查詢超時、CPU 飆升改用游標分頁、或限制最大頁碼
未關閉游標連接洩漏、內存溢出用 try-with-resources 或 .into(list) 自動關閉