【MongoDB】MongoDB-Change Streams

折月煮酒 提交于 2020-03-01 00:34:13

前言

Change Stream是从mongodb3.6版本开始支持的一种新特性,是mongodb向应用发布数据变更的一种方式,即数据库中有任何数据变化,应用端都可以得到通知,类似于触发器的概念

方案思路

MongoClient去订阅mongodb数据库中某张表最新事件变化,类似于以事件驱动机制对collection变化做监听,化主动为被动,只需要被动等待collection变化消息

Change Stream 与 Tailing Oplog 对比,参考:http://www.mongoing.com/archives/29921

Java版本demo

public class MongodbStreamResumeToken {
    /**
     * 用于模拟断点续传的存储,后期可以存储redis缓存中
     */
    private HashMap hashMap = new HashMap();

    public MongoDatabase getDatabase(){
        MongoDatabase database = null;
        MongoClient mongoClient = null;
//        MongoCredential credential = MongoCredential.createScramSha1Credential("userName","source","password");
        MongoClientOptions.Builder build = new MongoClientOptions.Builder();
        build.connectionsPerHost(50);
        build.threadsAllowedToBlockForConnectionMultiplier(50);
        build.maxWaitTime(1000*60*2);
        build.connectTimeout(1000*60);
        MongoClientOptions mongoClientOptions = build.build();
        ServerAddress serverAddress = new ServerAddress("127.0.0.1",27112);
        mongoClient = new MongoClient(serverAddress,mongoClientOptions);
        database = mongoClient.getDatabase("seal");
        return database;
    }

    /**
     * 
     * @param collection 需要监听的集合
     */
    public void WatchDb(String collection) {
        MongoDatabase database = getDatabase();
        MongoCollection<Document> paper = database.getCollection(collection);
        //FullDocument.UPDATE_LOOKUP选项启用后,在update变更事件中将携带完整的文档数据(FullDocument)。
        MongoCursor<ChangeStreamDocument<Document>> cursor = null;
        //需要存取resumeToken,便于后期断点续传(监控程序意外关闭,可以根据resumeToken,继续同步关闭期间内的增删操作)
        hashMap.put(collection,"{ \"_data\" : { \"$binary\" : \"gl5XgIsAAAABRmRfaWQAZF5WksTLMTgwnAlAZQBaEATiSsNQNiVOwb+UWStKFczoBA==\", \"$type\" : \"00\" } }");
        Object temp = hashMap.get(collection);
        //断点续传
        if (temp != null){
            String afterToken = String.valueOf(temp);
            BsonDocument resumeToken = BsonDocument.parse(afterToken);
            cursor = paper.watch().fullDocument(FullDocument.UPDATE_LOOKUP).resumeAfter(resumeToken).iterator();
        }else {
            cursor = paper.watch().fullDocument(FullDocument.UPDATE_LOOKUP).iterator();
        }
        //cursor.hasNext()这个方法是阻塞等待新的消息进来的,可以放心使用
        while (cursor.hasNext()) {
            ChangeStreamDocument<Document> next = cursor.next();
            JSONObject jsonObject = new JSONObject();
            if (StringUtils.isEmpty(next.getFullDocument())){
                jsonObject.put("o", null);
            }else {
                jsonObject.put("o", next.getFullDocument().toJson());
            }
            jsonObject.put("ns", next.getNamespace().getFullName());
            jsonObject.put("op", next.getOperationType().getValue());
            //操作类型
            log.info(next.getOperationType().getValue());
            //收集变更信息,通过mq异步处理
            log.info(JSON.toJSONString(next));

            //存储断点续传
            BsonDocument newResumeToken = next.getResumeToken();
            System.out.println(newResumeToken.toString());
            hashMap.put(collection,newResumeToken.toString());
        }
    }
}

 

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!