国产精品久久99,51久久成人国产精品麻豆,亚洲欧洲免费三级网站,最近中文字幕mv,重口老太大和小伙乱

首頁>資訊 > 正文

mongodb 深度分頁優(yōu)化思路之cursor游標

2023-06-23 20:30:57來源:博客園

mongodb 沒有官方的游標滾動實現(xiàn)深度分頁功能,建議的都是選擇出一個字段,如_id,然后每次查詢時限制該字段,而不進行分頁處理。

也沒有看到更優(yōu)的實現(xiàn)方式,本文做一個大膽的假設,自行實現(xiàn)滾動分頁功能。供大家思路參考。


(資料圖)

但是猜想可以自行實現(xiàn)一個,簡單思路就是,第一次查詢時不帶limit進行查詢?nèi)繑?shù)據(jù),然后自己通過cursor迭代出需要的行數(shù)后返回調(diào)用端,下次再調(diào)用時,直接取出上一次的cursor,再迭代limit的數(shù)量返回。

優(yōu)勢是只需計算一次,后續(xù)就直接復用結(jié)果即可。該功能需要有mongodb的clientSession功能支持。

但是需要復雜的自己維護cursor實例,打開、關閉、過期等。稍微管理不好,可能就客戶端內(nèi)存泄漏或者mongo server內(nèi)存泄漏。

實踐步驟:

1. 引入mongo 驅(qū)動:

                    org.mongodb            mongodb-driver-sync            4.4.2                            org.mongodb            mongodb-driver-core            4.4.2                            org.mongodb            bson            4.4.2        

注意版本不匹配問題,所以要引入多個包。

2. 創(chuàng)建測試類:

驗證接入mongo無誤,且造入適量的數(shù)據(jù)。

import static com.mongodb.client.model.Filters.eq;import com.mongodb.ConnectionString;import com.mongodb.MongoClientSettings;import com.mongodb.WriteConcern;import com.mongodb.client.*;import com.mongodb.client.result.InsertOneResult;import org.bson.Document;import org.junit.Before;import org.junit.Test;import org.openjdk.jmh.annotations.Setup;public class MongoQuickStartTest {    private MongoClient mongoClient;    @Before    public void setup() {        // Replace the placeholder with your MongoDB deployment"s connection string        String uri = "mongodb://localhost:27017";        MongoClientSettings options = MongoClientSettings.builder()                .applyConnectionString(new ConnectionString(uri))                .writeConcern(WriteConcern.W1).build();        mongoClient = MongoClients.create(options);    }    @Test    public void testFind() {//        ConnectionString connectionString = new ConnectionString("mongodb://localhost:27017");//        MongoClient mongoClient = MongoClients.create(connectionString);        // Replace the placeholder with your MongoDB deployment"s connection string        MongoDatabase database = mongoClient.getDatabase("local");        MongoCollection collection = database.getCollection("test01");        Document doc = collection.find(eq("name", "zhangsan1")).first();        if (doc != null) {            System.out.println(doc.toJson());        } else {            System.out.println("No matching documents found.");        }    }    @Test    public void testInsert() {        Document body = new Document();        long startId = 60011122212L;        MongoDatabase database = mongoClient.getDatabase("local");        MongoCollection collection = database.getCollection("test01");        int i;        for (i = 0; i < 500000; i++) {            String id = (startId + i) + "";            body.put("_id", id);            body.put("name", "name_" + id);            body.put("title", "title_" + id);            InsertOneResult result = collection.insertOne(body);        }        System.out.println("insert " + i + " rows");    }}

3. 創(chuàng)建cursor的查詢實現(xiàn)類并調(diào)用

基于springboot創(chuàng)建 controller進行會話測試,使用一個固定的查詢語句進行分頁測試。

import com.mongodb.ConnectionString;import com.mongodb.MongoClientSettings;import com.mongodb.WriteConcern;import com.mongodb.client.*;import org.bson.Document;import org.springframework.stereotype.Service;import java.util.ArrayList;import java.util.List;import java.util.Map;import java.util.concurrent.ConcurrentHashMap;@Servicepublic class MongoDbService {    private MongoClient mongoClient;    // 所有游標容器,簡單測試,真正的管理很復雜    private Map> cursorHolder            = new ConcurrentHashMap<>();    public void ensureMongo() {        // Replace the placeholder with your MongoDB deployment"s connection string        String uri = "mongodb://localhost:27017";        MongoClientSettings options = MongoClientSettings.builder()                .applyConnectionString(new ConnectionString(uri))                .writeConcern(WriteConcern.W1).build();        mongoClient = MongoClients.create(options);    }    // 特殊實現(xiàn)的 cursor 滾動查詢    public List findDataWithCursor(String searchAfter, int limit) {        ensureMongo();        MongoDatabase database = mongoClient.getDatabase("local");        MongoCollection collection = database.getCollection("test01");        List resultList = new ArrayList<>();        MongoCursor cursor = cursorHolder.get(searchAfter);        if(cursor == null) {            // 第一次取用需要查詢,后續(xù)直接復用cursor即可            cursor = collection.find().sort(new Document("name", 1)).iterator();            cursorHolder.put(searchAfter, cursor);        }        int i = 0;        // 自行計數(shù),到達后即返回前端        while (cursor.hasNext()) {            resultList.add(cursor.next());            if(++i >= limit) {                break;            }        }        if(!cursor.hasNext()) {            cursor.close();            cursorHolder.remove(searchAfter);        }        return resultList;    }}

應用調(diào)用controller:

@Resource    private MongoDbService mongoDbService;    @GetMapping("/mongoPageScroll")    @ResponseBody    public Object mongoPageScroll(@RequestParam(required = false) String params,                                  @RequestParam String scrollId) {        return mongoDbService.findDataWithCursor(scrollId, 9);    }

測試方式,訪問接口:http://localhost:8080/hello/mongoPageScroll?scrollId=c,然后反復調(diào)用(下一頁)。

如此,只要前端第一次查詢時,不存在cursor就創(chuàng)建,后續(xù)就直接使用原來的結(jié)果。第一次可能慢,第二次就很快了。

結(jié)論,是可以簡單實現(xiàn)的,但是生產(chǎn)不一定能用。因為,如何管理cursor,絕對是個超級復雜的事,何時打開,何時關閉,超時處理,機器宕機等,很難解決。

關鍵詞:

責任編輯:

免責聲明

頭條新聞

精彩推送

新聞推送