常见问题解答
本页内容
- 通用
- 如果无法连接到 MongoDB 实例怎么办?
- 为什么 Java 驱动程序中有两种类型的
MongoClient
? - 我应该使用哪种类型的
MongoClient
? - 如何使用
MongoClientSettings
类? - Java 驱动程序中的连接池是如何工作的?
- 如何防止 "java.lang.NoClassDefFoundError: com/mongodb/MongoClient" 错误?
- 如何防止 "com.mongodb.MongoSecurityException" 错误?
- 如何防止 "IllegalArgumentException: Invalid BSON field name" 错误?
- 如何防止 "IllegalStateException: state should be: open" 错误?
- POJOs
- 我必须自己指定 ID 字段值吗?
- ID 字段可以是复合键吗?
- 我可以在 POJO 访问器中使用多态吗?
- 什么是区分符?
- 我能否控制
LocalDate
的序列化? - 能否将
java.util.Date
序列化为格式为yyyy-mm-dd的字符串? - 能否使POJO直接读写字段,而不使用任何getter/setter?
- 能否混合使用私有、受保护和公开的setter和getter?
- 如何解决: "org.bson.codecs.configuration.CodecConfigurationException: Can't find a codec for class X." 的问题?
- 如何指定特定POJO类的集合名称?有注解吗?
- 旧版API
- 如何使用旧版API连接到我的MongoDB实例?
- 如何使用旧版
MongoClientOptions
和MongoClientURI
类? - 支持
一般
如果我无法连接到MongoDB实例怎么办?
如果您连接到MongoDB部署遇到问题,请查看连接故障排除指南以获取可能的解决方案。
为什么 Java 驱动程序中有两种类型的MongoClient
在Java驱动程序中?
存在两种类型的MongoClient
,因为我们希望为新手提供一个更清晰的API,避免包含多个CRUD API的混淆。我们希望确保新的CRUD API能够在Java 9中引入的Java模块支持下工作的Java包结构中可用。
我应该使用哪种类型的 MongoClient
?
新应用程序通常使用 com.mongodb.client.MongoClient
接口,它支持
使用
MongoClientSettings
和ConnectionString
进行配置。您可以通过com.mongodb.client.MongoClients
类中定义的工厂方法来创建此接口的实例。使用
MongoDatabase
的 CRUD API,然后从MongoCollection
如果您需要支持旧版 API,请使用 com.mongodb.MongoClient
类,它支持
使用
MongoClientOptions
和MongoClientURI
进行配置使用
DB
的 CRUD API,然后从DBCollection
。您可以通过getDB()
方法访问此 API。
对于需要新旧 API 混合使用的应用程序,com.mongodb.MongoClient
也支持
使用
MongoClientSettings
和ConnectionString
进行配置,唯一的区别是您通过构造函数而不是工厂类来创建实例。使用
MongoDatabase
的 CRUD API,然后从MongoCollection
。您可以通过getDatabase()
方法访问此 API。
我该如何使用 MongoClientSettings
类?
您可以使用 MongoClientSettings
类来指定 MongoClient
实例的配置。要构建 MongoClientSettings
实例,请使用 MongoClientSettings.Builder
类。
以下是我们文档中展示如何使用 MongoClientSettings
类执行不同任务的章节
有关 MongoClientSettings
类的更多信息,请参阅MongoClientSettings 的 API 文档.
Java 驱动中连接池是如何工作的?
每个 MongoClient
实例都为其 MongoDB 布局中的每个服务器内置一个连接池。连接池根据需要打开套接字,以支持多线程应用程序中并发执行 MongoDB 操作。
每个连接池的最大大小由 maxPoolSize
选项设置,默认为 100
。如果连接到服务器的已使用连接数达到 maxPoolSize
的值,则对该服务器的下一个请求将等待,直到连接可用。
每个 MongoClient
实例在其 MongoDB 布局中的每个服务器上额外打开两个套接字,用于监控服务器状态。
例如,连接到 3 节点副本集的客户端打开 6 个监控套接字。它还打开所需的套接字数量,以在每个服务器上支持应用程序的线程,最多不超过 maxPoolSize
的值。如果 maxPoolSize
为 100
且应用程序仅使用主节点(默认),则仅主连接池增长,最多可以有 106
个总连接。如果应用程序使用 读取偏好 来查询辅助节点,则它们的池也会增长,最多可以有 306
个总连接。
此外,连接池受到速率限制,这意味着每个连接池在任何时候最多可以并行创建 maxConnecting
个连接。在以下情况下,任何额外的线程都会停止等待:
现有线程完成创建连接,或现有连接被退回池中。
由于连接创建的速率限制,驱动器重用现有连接的能力得到提高。
您可以使用 minPoolSize
选项设置每个服务器并发连接的最小数量,该选项默认为 0
。连接池将使用此数量的套接字初始化。如果由于任何网络错误关闭套接字,导致套接字总数(包括使用中和空闲的)低于最小值,则将打开更多套接字,直到达到最小值。
您可以使用 maxIdleTimeMS
选项设置连接在池中保持空闲的最大毫秒数,该选项默认为 0
(无限制)。
以下默认的 MongoClient
配置适用于大多数应用程序
MongoClient client = new MongoClient("<connection string>")
为每个进程创建一个客户端,并重用它执行所有操作。为每个请求创建新的客户端是一个常见的错误,这非常低效。
为了在单个进程中支持大量并发 MongoDB 操作,您可以增加 maxPoolSize
。一旦池达到其最大大小,额外的线程将等待套接字可用。
驱动程序不限制等待套接字变为可用的线程数量,在负载高峰期间限制池的大小以进行队列绑定是应用程序的责任。线程等待由 waitQueueTimeoutMS
选项指定的时长,该选项默认为 120000
,即 120 秒。
等待时间超过由 waitQueueTimeoutMS
定义的时间长度的线程将引发连接错误。如果您认为在负载高峰期间限制操作时间比完成每个操作更重要,请使用此选项。
当任何线程调用 MongoClient.close()
时,驱动程序将关闭所有空闲套接字,并在它们返回到池中时关闭所有正在使用的套接字。
如何防止 "java.lang.NoClassDefFoundError: com/mongodb/MongoClient" 错误?
当您的 Java 运行时环境无法在运行时定位一个类文件时,您可能会遇到 java.lang.NoClassDefFoundError
异常。当您尝试运行使用 MongoDB Java 驱动的应用程序代码时,必须在类路径上包含适当的驱动程序 JAR 文件。
如果您在将 Java 驱动程序 JAR 文件添加到类路径后收到此错误,请在您的环境中检查以下项
JAR 文件位于类路径指定的位置。
类路径语法正确。
如果您在环境变量中定义了类路径,Java 运行时环境使用该变量。
如果您使用依赖管理器,它不会报告任何无法解决的冲突。
技巧
此错误包含包和类名,这可以帮助您确定哪个驱动程序 JAR 可能未包含在您的类路径中。要找到错误引用的驱动程序 JAR,请检查 API 文档 中的每个条目。
如何防止 "com.mongodb.MongoSecurityException" 错误?
当您在连接到 MongoDB 部署时指定无效或不正确格式的凭据,您的应用程序可能会抛出此异常。
当您尝试连接到 MongoDB 部署时收到此错误,请检查以下代码中的项目
如何防止 "IllegalArgumentException: Invalid BSON field name" 错误?
如果您的应用程序在将不正确格式化的文档传递给操作时抛出此异常,并且您正在使用版本 v4.7 或更早的驱动程序。
注意
在版本 v4.8 及以后的驱动程序中,此错误消息已被包含更多具体细节的错误消息所替换。
例如,当您调用更新操作并错误地省略更新操作符时,驱动程序会抛出此错误,如下面的代码示例所示
// incorrectly formatted update document collection.updateOne( new Document().append("name", "fizz"), new Document().append("name", "buzz") );
要避免此错误,请使用适当操作的构建器类。驱动程序提供构建器类来创建用于 MongoDB 操作的语法正确的 BSON。以下示例可以正确地使用构建器类表示,如下面的代码示例所示
// Builder class imports import static com.mongodb.client.model.Filters.*; import static com.mongodb.client.model.Updates.*; // ... collection.updateOne(eq("name", "fizz"), set("name", "buzz"));
要了解有关可用构建器类的更多信息,请参阅 构建器 文档。
如何防止 "IllegalStateException: state should be: open" 错误?
如果在关闭与MongoDB连接的 MongoClient
实例上调用操作,可能会遇到此异常。一旦在 MongoClient
上调用 close()
方法,对该实例的任何进一步的操作调用都会抛出此异常。
为了避免此异常,不要在调用 close()
的代码之后对 MongoClient
实例进行操作。
技巧
在某些情况下,关闭 MongoClient
实例的代码可能难以定位。为了找到此异常的潜在来源,请搜索以下情况:
对
MongoClient
实例的close()
调用在声明
MongoClient
的 try-with-resources 语句作用域之外对MongoClient
实例进行操作调用
如果您的应用程序使用框架(如Spring Boot)来管理 MongoClient
,请检查框架文档以找到管理连接行为的最佳实践。
要了解有关从Spring Boot访问MongoDB的更多信息,请参阅Spring Boot和MongoDB。
POJOs
我必须自己指定ID字段值吗?
不,PojoCodecProvider
会自动生成一个 ObjectId。
ID字段可以是复合键吗?
是的。例如,请参阅我们的实现:我们的实现
我可以在POJO访问器中使用多态吗?
是的,可以通过使用区分器(discriminator)来实现。
什么是区分器?
区分器是一种属性,用于标识特定的文档模式。您可以使用它来实现继承,并在同一集合或父文档(如果嵌入子文档)中存储多种类型的文档。
例如,如果您有一个Java中的Event
类,并扩展了它,例如MachineEvent
或NetworkEvent
,使用区分器可以确定PojoCodecProvider
必须使用哪个类来序列化和反序列化文档。
有关更多信息,请参阅POJO自定义指南。
我能否控制LocalDate
的序列化?
是的,3.7 Java驱动程序添加了对JSR-310 Instant
、LocalDate
和LocalDateTime
的原生支持。
能否将 java.util.Date
对象序列化为格式为 yyyy-mm-dd 的字符串?
是的,您可以为此类构建自己的编解码器并将其添加到注册表中。
将编解码器添加到提供商列表的第一个位置,在默认编解码器注册表和 PojoCodecProvider
之前。
CodecRegistry registry = CodecRegistries.fromRegistries( CodecRegistries.fromCodecs( new MyDateAsStringCodec()), MongoClientSettings.getDefaultCodecRegistry(), fromProviders(pojoCodecProvider));
我能否使 POJO 直接读写字段,而不使用任何 getter/setter?
您可以配置 PojoCodecProvider
使用 SET_PRIVATE_FIELDS_CONVENTION
,如果不存在公共设置器,则通过反射设置私有字段。
我能否混合使用私有、受保护的和公共的 setter 和 getter?
编号。本地POJO编解码器假定每个字段的getter/setter具有相同的修饰符。
例如,以下方法在编码过程中抛出异常
private String getField(); public String setField(String x);
如何修复:"org.bson.codecs.configuration.CodecConfigurationException: 无法找到类X的编解码器。"?
此异常意味着您必须为该类注册编解码器,因为目前没有。
如何指定特定POJO类的集合名称?是否有注解?
没有注解。我们建议在您的类中添加一个静态字符串,如下所示
public class Person { public static final String COLLECTION_NAME = "people"; }
以下代码片段指定了特定POJO类的集合名称
database.getCollection(Person.COLLECTION_NAME, Person.class);
旧版API
如何使用旧版API连接到我的MongoDB实例?
以下示例显示了如何使用旧版API和当前API连接到MongoDB实例。
假设我们正在连接到一个只包含此文档的集合
{"_id": 1, "val": 1}
MongoClient client = new MongoClient(URI); DB db = client.getDB(DATABASE); DBCollection col = db.getCollection(COLLECTION); // Retrieves one document in the collection and prints it DBObject doc = col.find().one(); System.out.println(doc.toString());
MongoClient client = MongoClients.create(URI); MongoDatabase db = client.getDatabase(DATABASE); MongoCollection<Document> col = db.getCollection(COLLECTION); // Prints the first document retrieved from the collection as JSON Document doc = col.find().first(); System.out.println(doc.toJson());
前面代码片段的输出类似于以下内容
{"_id": 1, "val": 1}
有关前面示例中使用的旧版类和方法的更多信息,请参阅以下API文档页面
有关旧版API和当前API之间差异的列表,请参阅从旧版API迁移页面。
如何使用旧版的MongoClientOptions
和MongoClientURI
类?
以下是一个示例,展示了如何使用旧版的MongoClientOptions
和MongoClientURI
类设置您的写关注点
MongoClientURI mongoURI = new MongoClientURI(URI, MongoClientOptions.builder() .writeConcern(WriteConcern.W1)); MongoClient client = new MongoClient(mongoURI);
MongoClientSettings options = MongoClientSettings.builder() .applyConnectionString(new ConnectionString(URI)) .writeConcern(WriteConcern.W1).build(); MongoClient client = MongoClients.create(options);
有关前面示例中使用的旧版类和方法的更多信息,请参阅以下API文档页面
有关旧版API和当前API之间差异的列表,请参阅从旧版API迁移页面。
支持
如果您在这里找不到问题的答案,请尝试查看问题和帮助部分中列出的论坛和支持渠道。