MongoDB打开连接问题

6

我在mongo控制台中有以下日志:

Tue Jul 23 17:20:01.301 [initandlisten] waiting for connections on port 27017
Tue Jul 23 17:20:01.401 [websvr] admin web console waiting for connections on port 28017
Tue Jul 23 17:20:01.569 [initandlisten] connection accepted from 127.0.0.1:58090 #1 (1 connection now open)
Tue Jul 23 17:20:01.570 [initandlisten] connection accepted from 127.0.0.1:58089 #2 (2 connections now open)
Tue Jul 23 17:20:21.799 [initandlisten] connection accepted from 127.0.0.1:58113 #3 (3 connections now open)
....
....
....

同样,日志继续记录,现在已经到了112。每次我启动Mongo服务器时都会发生这种情况。我的代码中只有一个单例连接。可能出了什么问题:

public static DB getConnection(String databaseName) throws AppConnectionException {

    if (null != db) {
        Logger.debug("Returning existing db connection...!");
        return db;
    }

    Logger.debug("Creating new db connection...!");
    final String connStr = PropertyRetreiver.getPropertyFromConfigurationFile("rawdata.url");

    try {

        final MongoClientURI uri = new MongoClientURI(connStr);
        final MongoClient client = new MongoClient(uri);
        db = client.getDB(databaseName);

    } catch (UnknownHostException e) {
        throw new AppConnectionException(
                "Unable to connect to the given host / port.");
    }

    return db;
}

有多种方法吗?你能让它“同步”吗? - bsd
我的DAO将调用这个连接器类的方法来获取连接。此外,这个连接是一个静态单例连接,因此我希望在任何给定时间只有一个连接...那么,为什么我需要在这里同步??? - popcoder
1个回答

阿里云服务器只需要99元/年,新老用户同享,点击查看详情
8

MongoClient 内部有一个连接池,最大连接数可以配置(默认为 100)。您可以通过使用 MongoClientOptions 来设置它,如下所示:

MongoClientOptions options = MongoClientOptions.builder()
                .connectionsPerHost(100)
                .autoConnectRetry(true)
                .build();

然后在Mongo Java API v2.11.1中将这些选项提供给MongoClient。连接池中的连接保持打开状态(打开和关闭连接通常是昂贵的操作),以便以后可以重用。

我还建议使用enum重新设计您的MongoDB客户端单例,以避免在此方法上放置synchronized

以下是我的想法草图:

public enum MongoDB {
    INSTANCE;

    private static final String MONGO_DB_HOST = "some.mongohost.com";
    private Mongo mongo;
    private DB someDB;

    MongoDB() {

        MongoClientOptions options = MongoClientOptions.builder()
                .connectionsPerHost(100)
                .autoConnectRetry(true)
                .readPreference(ReadPreference.secondaryPreferred())
                .build();

        try {
            mongo = new MongoClient(MONGO_DB_HOST, options);
        } catch (UnknownHostException e) {
            e.printStackTrace();
        }

        someDB = mongo.getDB("someDB");
         //authenticate if needed
         //boolean auth = someDB.authenticate("username", "password".toCharArray());
         //if(!auth){
         //     System.out.println("Error Connecting To DB");
         //}        
    }

    public DB getSomeDB() {
        return someDB;
    }

    //call it on your shutdown hook for example 
    public void close(){
        mongo.close();
    }
}

随后,您可以通过以下方式访问您的数据库:

MongoDB.INSTANCE.getSomeDB().getCollection("someCollection").count();

我希望在任何时候只有一个活动连接,这就是为什么我将其设置为静态单例的原因。配置连接数如何帮助解决这个问题? - popcoder
另外,你能否更新一下你提到的重构内容? - popcoder
你的请求是如何发起的?是通过浏览器提交的吗?请在问题中描述流程。关于单例模式进行了更新。 - Alex P
2
明白了。据我所知,Mongo在连接池中开始时有一个打开的连接。因此,如果这个进程没有运行访问MongoClient实例的线程,那么它应该会重用同一个连接。我还会检查是否有其他进程(除了您计划的Akka作业)打开了连接。尝试将连接数限制为2,例如,只是为了看看是否确实只有您的进程(您不应该看到超过2个连接)。在进程关闭时调用MongoClient的close方法。 - Alex P
@AlexP 在关闭期间使用类似于 'MongoDBClass.INSTANCE.close()' 的Close方法,我不理解。在重新部署项目或手动重启tomcat服务器时,我该如何调用该方法呢?是否有代码可以预测服务器停止并调用上述Close方法。否则就没有地方调用Close方法。因为当我调用Close方法后,直到关闭服务器并再次启动它之前,连接才不会重新打开。 - Vicky
@Vicky,Web服务器有钩子可以实现并优雅地关闭数据库连接。您可以实现ServletContextListener并从contextDestroyed方法中调用MongoDB.INSTANCE.close()。请参见https://tomcat.apache.org/tomcat-8.0-doc/servletapi/index.html。您应该在web.xml中定义此侦听器或使用注释。 - Alex P

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,