【问题标题】:MongoDB: No server chosen by ReadPreferenceServerSelectorMongoDB:ReadPreferenceServerSelector 没有选择服务器
【发布时间】:2015-06-25 11:16:06
【问题描述】:

最近我正在使用新发布的 mongodb java 异步驱动程序。我正在写一些简单的测试代码,分别是:

    MongoClient mongoClient = MongoClients.create();
    System.out.println("database has been connected!");

    SingleResultCallback<Void> callbackWhenFinished = new SingleResultCallback<Void>() {
        @Override
        public void onResult(final Void result, final Throwable t) {
            System.out.println("Operation Finished!");
        }
    };

    mongoClient.listDatabaseNames().forEach(new Block<String>() {
        @Override
        public void apply(final String s) {
            System.out.println(s);
        }
    }, callbackWhenFinished);

然而,回调函数没有被调用,控制台输出为:

2015 年 4 月 18 日下午 10:50:27 com.mongodb.diagnostics.logging.JULLogger 日志消息:已创建集群 设置 {hosts=[localhost:27017], mode=SINGLE, requiredClusterType=UNKNOWN, serverSelectionTimeout='30000 ms', maxWaitQueueSize=500}
数据库已连接! 2015 年 4 月 18 日下午 10:50:28 com.mongodb.diagnostics.logging.JULLogger 日志消息:否 选择的服务器 集群中的 ReadPreferenceServerSelector{readPreference=primary} 描述 ClusterDescription{type=UNKNOWN, connectionMode=SINGLE, 全部=[服务器描述{地址=本地主机:27017,类型=未知, 状态=连接}]}。在超时前等待 30000 毫秒

所以你可以看到没有调用回调函数。有谁知道为什么?

【问题讨论】:

    标签: mongodb mongodb-java


    【解决方案1】:

    我认为您应该每次在 finally 子句中关闭 MongoClient 对象。对我来说,发生了同样的问题,当我在命令行中关闭连接时,我看到很多连接都是打开的。

    尝试这样的事情(我使用 mongodb 3.0.7 和 mongo-java-driver 3.1.0):

    package com.mkyong.core;
    
    import org.bson.Document;
    import org.junit.Test;
    
    import com.mongodb.Block;
    import com.mongodb.MongoClient;
    import com.mongodb.client.FindIterable;
    import com.mongodb.client.MongoDatabase;
    
    /**
     * Unit test for simple App.
     */
    public class AppTest {
    
        @Test
        public void firstTest() throws Exception {
            MongoClient mongoClient = null;
            try {
                mongoClient = new MongoClient("127.0.0.1", 27017);
                MongoDatabase db = mongoClient.getDatabase("census");
                FindIterable<Document> iterable = db.getCollection("states").find();
                iterable.forEach(new Block<Document>() {
                    @Override
                    public void apply(final Document document) {
                        System.out.println(document);
                    }
                });
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                try {
                    mongoClient.close();
                } catch (Exception e2) {
                }
            }
        }
    
    }
    

    有了这个,我可以毫无问题地使用我的连接。

    【讨论】:

      【解决方案2】:

      简短的回答是最终会调用您的回调。

      对于长答案,让我们来看看你的代码:

          MongoClient mongoClient = MongoClients.create();
          System.out.println("database has been connected!");
      

      MongoClient 不会在内部连接池尝试连接的后台阻止等待与 MongoDB 的连接。从您的日志中,我可以看到您的默认 serverSelectionTimeout 为 30000 毫秒。

      下一步您将执行println 立即输出“数据库已连接!”无论如何都会被打印出来。

      最后,您调用listDatabaseNames(),但不清楚的是是否有任何等待回调被调用。如果您添加一个闩锁然后等待响应,那么您将看到回调被调用,例如:

        System.out.println("======= Start =======");
      
        MongoClient mongoClient = MongoClients.create();
      
        final CountDownLatch latch = new CountDownLatch(1);
      
        SingleResultCallback<Void> callbackWhenFinished = new SingleResultCallback<Void>() {
            @Override
            public void onResult(final Void result, final Throwable t) {
                System.out.println("Operation Finished!");
                if (t != null) {
                    System.out.println("listDatabaseNames() errored: " + t.getMessage());
                }
                latch.countDown();
            }
        };
      
        mongoClient.listDatabaseNames().forEach(new Block<String>() {
            @Override
            public void apply(final String s) {
                System.out.println(s);
            }
        }, callbackWhenFinished);
      
        latch.await();
      
        // close resources
        mongoClient.close();
        System.out.println("======= Finish =======");
      

      现在使用锁存器 await() 直到回调被调用,现在我们应该看到以下两种情况之一发生:

      1. 没有可用的 MongoDB。 它最终会调用回调并打印出错误。它将等到serverSelectionTimeout 超时。

      2. 有一个可用的 MongoDB。 它最终会连接,对于每个数据库,它将应用Block 并打印出数据库名称,然后最后它会调用它已完成的回调信号。

      【讨论】:

      • 为什么要显式调用wait,程序不应该等到所有用户线程都完成了吗?
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-08-26
      • 1970-01-01
      • 2019-03-04
      • 2021-10-11
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多