将MongoDb与Javaservlet结合使用

将MongoDb与Javaservlet结合使用,java,mongodb,servlets,Java,Mongodb,Servlets,我在Javaservlet上使用MongoDB时遇到了一个问题 我的servlet有许多方法(~20)来访问数据库以检索和添加数据。一个非常简单的例子: public static String getSomething(String s) { String json = "[]"; JSONArray jsonArray = new JSONArray(); DBCollection table; try { Mongo mongo = new Mongo("loca

我在Javaservlet上使用MongoDB时遇到了一个问题

我的servlet有许多方法(~20)来访问数据库以检索和添加数据。一个非常简单的例子:

public static String getSomething(String s) {
  String json = "[]";
  JSONArray jsonArray = new JSONArray();
  DBCollection table;

  try {
    Mongo mongo = new Mongo("localhost", 27017);
    DB db = mongo.getDB( "myDb" );  
        BasicDBObject quoteQuery = new BasicDBObject("abc", abc);
    DBCursor cursor = table.find(quoteQuery);

    try {
      while(cursor.hasNext()) {
        jsonArray.put(cursor.next());
      }
    } finally {
      cursor.close();
    }

// ...
现在的问题是,当这个Javaservlet部署在linux服务器上时,它可以正常工作10天左右

之后它崩溃了

当我转到var/log目录中的mongodb.log时,会得到以下重复输出:

“连接被拒绝,因为打开的连接太多”

我不知道现在在哪里编辑东西,也不知道如何处理这个问题。我曾尝试增加服务器中打开连接的限制,但仍然有相同的结果


有什么建议吗?

您应该非常谨慎地创建Mongo对象,理想情况下,每个类加载器在任何时候都只能创建一个Mongo对象。为了减少Mongo对象的数量,可以在servlet的init方法中创建它,并在每次调用时重用该实例

编辑:刚刚看了一下我们的代码,我们使用一个经典的单例类来管理Mongo实例(并且总是使用该类的
getInstance()
方法来获取
Mongo
),因为如果你的应用程序中有多个servlet/entrypoints,那么只要使用
init()
仍然会为每个servlet生成一个实例,但仍然无法满足API文档中@FredClose引用的手册部分:

公共类Mongo扩展对象


具有内部连接池的数据库连接对于大多数应用程序,整个JVM都应该有一个Mongo实例

您可以创建Mongo对象一次,而不是在每次getSomething调用时创建它

public SomeClass{
static Mongo mongo = new Mongo("localhost", 27017);
static DB db = mongo.getDB( "myDb" );  

public static String getSomething(String s) {
String json = "[]";
JSONArray jsonArray = new JSONArray();
DBCollection table;
try {

BasicDBObject quoteQuery = new BasicDBObject("abc", abc);
DBCursor cursor = table.find(quoteQuery);

while(cursor.hasNext()) {
  jsonArray.put(cursor.next());

}

}

实际上,理想的情况是根本不使用静态访问,而是从中央控制器注入DB对象。

您正在MongoDB中创建连接,但没有关闭连接。对于任何数据库来说,关闭连接都是非常重要的,否则它将达到最大限制,您将无法正确执行程序。我希望以下代码会有所帮助:

        public static String getSomething(String s) {
    String json = "[]";
    JSONArray jsonArray = new JSONArray();

    try {

        MongoClient mongoClient = new MongoClient("localhost", 27017);
        DB db = mongoClient.getDB("myDb");
        DBCollection collection = db.getCollection("NAME OF YOUR COLLECTION");
        BasicDBObject quoteQuery = new BasicDBObject("abc", "VARIABLE THAT YOU WANT TO FIND");

        DBCursor cursor = collection.find(quoteQuery);
        try {
            while (cursor.hasNext()) {
                jsonArray.put(cursor.next());
            }
        } finally {
            cursor.close();
        }
        mongoClient.close();
    } catch (Exception e) {
    }
    return jsonArray.toString();
}

在此代码中,“MongoClient”在其用途结束后关闭。

Arun Gupta‏@阿伦古普塔


新的示例显示了如何在#JavaEE7应用程序中使用Mongo:

根据上述问题,就像您为每个请求创建Mongo对象一样。我建议在整个应用程序中使用单个对象。为此,您可以找到“MongoClient和连接池”。 MongoClient将自动为您处理连接池

mongoClient=新的mongoClient(URI、connectionOptions)


在这里,mongoClient对象保存您的连接池,并根据需要为您的应用程序提供连接。您应该努力在应用程序初始化时创建此对象一次,并在整个应用程序中重新使用此对象与数据库通信。我们看到的最常见的连接池问题是应用程序太频繁地创建MongoClient对象,有时是在每个数据库请求上。如果您这样做,您将不会使用连接池,因为每个MongoClient对象都维护一个单独的池,而您的应用程序不会重用该池。

您是否得到解决问题的解决方案?为什么不在ServletContextListener中初始化它并将其设置为上下文的属性,这也会使我们的应用程序快速失败。在listener destroy方法中关闭它。@Pankaj这确实是一个更好的解决方案。谢谢,任何有兴趣的人都可以看看,例如,这不是问题的新答案。请先通读其他答案,然后写一个新的答案,如果你有新的贡献。@AmosM.Carpenter:是的,但这些基本信息将帮助其他人。虽然这不是新内容,但有助于详细理解我认为你误解了我的评论,这可能会更清楚。在旧问题上添加新内容的新答案没有问题。不过,你的回答没有添加任何新内容。已经建议使用单例,已经解释了该单例中的内部连接池,并且还解释了如果不使用单例,每次都将使用新连接池创建新对象的事实。如果您觉得某个特定答案需要更多信息,请添加评论或编辑答案。