以面向对象的方式管理 Java 中的 Mongodb 个连接

Managing Mongodb connections in Java as Object Oriented

如何使用多个 class 正确管理 mongo 连接?

例如,我有 4 个 classes 管理 4 个集合。

Collection1.class Collection2.class 等等

我所做的是在每个 class 中创建一个连接和关闭方法,这会减慢应用程序中某些交易的连接速度

将应用程序连接到数据库一次并开始使用所有 classes 实例的最佳方法是什么,而不是为每个 class 创建对象并分别连接每个实例?

您是正确的,每个 class(代表一个 MongoDB 集合)不应管理其自己的数据库连接。相反,您应该将数据库连接传递到 class - 通常在构造函数中。像这样:

class Animal {
    private String species;
    private String name;
    private int age;

    public Animal(DBObject dbObject) { ... }
}

class AnimalCollection {
    private final DBCollection collection;        

    public AnimalCollection(Database database) {
        collection = database.getCollection("animals");
    }

    public List<Animal> getAll() {
        List<Animal> animals 
        try (DBCursor cursor = collection.find(query)) {
            while (cursor.hasNext()) {
                animals.add(new Animal(cursor.next());
            }
        }
        return animals;
    }
}

创建所有集合的代码应该获取 MongoClient,连接到数据库并在退出时管理关闭连接。这样您就可以管理一个连接。

因此,管理集合的 class 可能如下所示:

class CollectionManager implements AutoCloseable {
    private final Database database;
    private final AnimalCollection animals;

    public CollectionManager(MongoClient client) {
        database = client.getDB("Zoo");
        animals = new AnimalCollection(database);
    }

    @Override
    public void close() {
        database.close();
    }
}

class 扩展 AutoCloseable 的原因是当您退出 try-with-resources 块时会自动调用 close。这将使您的代码更易于阅读和更安全。

这种方法还有一个很大的优势。您可以通过在构造函数中传递一个模拟的 Database 来对您的 classes 进行单元测试,并测试响应各种数据库输出的行为,而无需包含任何数据的实际数据库。

在应用程序中,具有所需连接数的单个 MongoClient 对象,使用 连接池 ,将适用于这种情况。连接池的默认值100,可以根据需要修改(或配置)。

mongo客户端对象可以在应用程序启动时创建,只有在应用程序关闭时才会关闭。这节省了与每个集合访问 class.

中的 mongo 客户端对象创建连接相关的资源

可以在整个应用程序中使用相同的 mongo 客户端对象。 单例 class(维护 mongo 客户端对象的一个​​实例)可以被应用程序中需要连接到 MongoDB 数据库服务器。


What is connection pooling?

In software engineering, a connection pool is a cache of database connections maintained so that the connections can be reused when future requests to the database are required. Connection pools are used to enhance the performance of executing commands on a database. Opening and maintaining a database connection for each user, especially requests made to a dynamic database-driven website application, is costly and wastes resources. In connection pooling, after a connection is created, it is placed in the pool and it is used again so that a new connection does not have to be established. If all the connections are being used, a new connection is made and is added to the pool. Connection pooling also cuts down on the amount of time a user must wait to establish a connection to the database.


示例代码:

/*
 * Manages the MongoClient object and its settings like host, port, connection pool, etc.
 */
public class DBAccess {

  private static MongoClient mongoClient;
  private static DBAccess dbAccess;

  // MongoClient with default settings
  // NOTE: the code will have only one of the constructors
  //private DBAccess() {
  //    final String connectionString = "mongodb://localhost:27017";
  //    this.mongoClient = MongoClients.create(connectionString);
  //}

  // MongoClient with custom settings.
  // Private constructor, so that the class can be instantiated outside this class.
  // NOTE: the code will have only one of the constructors
  private DBAccess() {

      MongoClientSettings settings =
          MongoClientSettings.builder()
              .applyToConnectionPoolSettings(builder ->
                   builder.maxSize(40).minSize(10))
             .applyToClusterSettings(builder ->
                   builder.hosts(Arrays.asList(new ServerAddress("localhost", 27017))))
            .build();

      mongoClient = MongoClients.create(settings);
  }

  public static MongoClient getConnection() {

      if (dbAccess == null) {
           dbAccess = new DBAccess();   
      }

      return mongoClient;
  }

  public static void closeDatabase() {
      mongoClient.close();
  }
}

/*
 * Class manages a collection.
 */
public class CollectionOneAccess {

  public static String COLLECTION_ONE = "collection_one";
  private MongoCollection<Document> collection;

  public CollectionOneAccess(MongoDatabase db) {    
      collection = db.getCollection(COLLECTION_ONE);
  }

  public void printOneDocument() {
      Document myDoc = collection.find().first();
      System.out.println(myDoc.toJson());
  }

  // other CRUD operations ...

}


// Usage of DBAcess and CollectionOneAccess classes:

private static final String APP_DATABASE = "abc_db";

public static void main(String [] args) {
    MongoDatabase database = DBAccess.getConnection().getDatabase(APP_DATABASE);
    CollectionOneAccess one = new CollectionOneAccess(database);
    one.printOneDocument();
    // ...
}

Mongo 客户端

MongoClient 对象用于连接到 MongoDB 服务器,使用 getDatebase() 方法访问数据库并使用集合。

com.mongodb.client.MongoClient接口:

A client-side representation of a MongoDB cluster. Instances can represent either a standalone MongoDB instance, a replica set, or a sharded cluster. Instance of this class are responsible for maintaining an up-to-date state of the cluster, and possibly cache resources related to this, including background threads for monitoring, and connection pools.

来自MongoDB Java documentation

MongoClient 实例代表一个数据库连接池;即使有多个线程,您也只需要 class MongoClient 的一个实例。

IMPORTANT: Typically you only create one MongoClient instance for a given MongoDB deployment (e.g. standalone, replica set, or a sharded cluster) and use it across your application. However, if you do create multiple instances:

  • All resource usage limits (e.g. max connections, etc.) apply per MongoClient instance.
  • To dispose of an instance, call MongoClient.close() to clean up resources.

以下代码使用默认设置创建一个MongoDB客户端连接对象,如主机("localhost")和端口(27017)、连接池等,以及连接到 Mongo 数据库实例并访问 testDB 数据库。

MongoClient mongoClient = MongoClients.create();
MongoDatabase database = mongoClient.getDatabase("testDB");

Mongo 客户端设置:

您可以使用 MongoClientSettings 显式指定其他设置来控制 MongoClient.

的行为
MongoClient mongoClient = MongoClients.create(MongoClientSettings settings)

ConnectionPoolSettings 对象指定与 Mongo 数据库服务器的连接池相关的所有设置。应用程序在创建客户端对象时创建此连接池。 ConnectionPoolSettings.BuilderConnectionPoolSettings 的构建器,具有指定连接池属性的方法。例如,maxSize​(int maxSize):允许的最大连接数(默认为 100)。其他方法包括minSizemaxConnectionIdleTime

使用连接池设置实例化 MongoClient 的代码:

MongoClientSettings settings = MongoClientSettings.builder()
                                   .applyToConnectionPoolSettings(builder -> 
                                       builder.maxSize(20))
                                   .build();
MongoClient mongoClient = MongoClients.create(settings);
// ...
// Verify the connection pool settings 
System.out.println("Pool size: " + 
    settings.getConnectionPoolSettings().getMaxSize());