FAQ
在此页面上
- 常规
- 如果无法连接到 MongoDB 实例怎么办?
- 为什么 Java 驱动程序中有两种类型的
MongoClient
? - 我应该使用哪种类型的
MongoClient
? - 如何使用
MongoClientSettings
类? - 连接池化在 Java 驱动程序中是如何工作的?
- 如何防止“java.lang.NoClassDefFoundError: com/mongodb/MongoClient”错误?
- 如何防止“com.mongodb.MongoSecurityException”错误?
- 如何防止出现“IllegalArgumentException: Invalid BSON 字段 name”(IllegalArgumentException: Invalid BSON 字段 name)错误?
- 如何防止出现“IllegalStateException: state should be: open”(IllegalStateException: state should be: open)错误?
- POJO
- 我是否必须自己指定 ID 字段值?
- ID 字段可以是复合键吗?
- 我可以在 POJO 访问器中使用多态性吗?
- 什么是鉴别器?
- 我能否控制
LocalDate
的序列化? - 我是否可以将
java.util.Date
序列化为yyyy-mm-dd格式的字符串? - 我是否可以让 POJO 直接读取/写入字段,并且根本不使用 getter/setter?
- 我是否可以混合使用私有、受保护和公共 setter 和 getter?
- 如何修复“org.bson.codecs.configuration.CodecConfigurationException:找不到 X 类的编解码器”?
- 如何为特定 POJO 类指定collection名称?有注释吗?
- Legacy API
- 如何使用旧版 API 连接到 MongoDB 实例?
- 如何使用旧版
MongoClientOptions
和MongoClientURI
类? - 支持
常规
如果无法连接到 MongoDB 实例怎么办?
如果您在连接到MongoDB 部署时遇到问题,请参阅《 连接故障排除指南》以了解可能的解决方案。
MongoClient
为什么Java驾驶员中有两种类型的 ?
有两种类型的 MongoClient
,因为我们希望为新用户提供更简洁的 API,避免因包含多个 CRUD API 而产生混乱。我们希望确保新的 CRUD API 以 Java 包结构提供,该结构能够很好地配合 Java 9 中引入的 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 驱动程序中是如何工作的?
对于 MongoDB 拓扑结构中的每个服务器,每个 MongoClient
实例都有一个内置连接池。连接池按需打开套接字以支持多线程应用程序中的并发 MongoDB 操作。
每个连接池的最大大小由 maxPoolSize
选项设置,默认值为 100
。如果某个服务器的在用连接数达到 maxPoolSize
值,则对该服务器的下一个请求将等待,直到出现可用连接。
每个MongoClient
实例会为 MongoDB 拓扑结构中的每个服务器再打开两个套接字,用于监控服务器的状态。
例如,连接到 3 节点副本集的客户端会打开 6 个监控套接字。 它还根据需要打开任意数量的套接字以支持每台服务器上的应用程序线程,最多可达maxPoolSize
的值。 如果maxPoolSize
为100
且应用程序仅使用主节点(默认),则只有主节点连接池会增长,总连接数最多可为106
。 如果应用程序使用读取偏好(read preference)来查询从节点,则其池也会增长,总连接数可能为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 字段 name”(IllegalArgumentException: Invalid BSON 字段 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”(IllegalStateException: state should be: open)错误?
如果您对MongoClient
实例调用关闭与 MongoDB 连接的操作,则可能会遇到此异常。 在MongoClient
上调用close()
方法后,对该实例的任何进一步操作调用都会抛出此异常。
要避免此异常,请不要在对 MongoClient
实例调用close()
的任何代码之后调用对实例的操作。
提示
在某些情况下,可能很难找到关闭MongoClient
实例的代码。 要查找此异常的潜在来源,请搜索以下案例:
在
MongoClient
实例上调用close()
对
MongoClient
实例的操作调用超出了声明MongoClient
的 try-with-resources 语句的范围
如果您的应用程序使用框架来托管MongoClient
(例如 Spring Boot),请查看该框架的文档,找到托管连接行为的最佳实践。
要了解有关从 Spring Boot 访问 MongoDB 的更多信息,请参阅Spring Boot 和 MongoDB。
POJO
我是否必须自己指定 ID 字段值?
不会, PojoCodecProvider
会自动生成 ObjectId。
ID 字段可以是复合键吗?
是的。 有关示例,请参阅 我们的实现
我可以在 POJO 访问器中使用多态性吗?
是的,通过使用鉴别器。
什么是鉴别器?
鉴别器是标识特定文档模式的属性。 您可以将其用于继承,并在同一collection或父文档中存储多种类型的文档(如果嵌入了子文档)。
例如,如果您有在 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,则通过反射设置私有字段。
我是否可以混合使用私有、受保护和公共 setter 和 getter?
不可以。原生 POJO 编解码器假定每个字段的 getter/setter 具有相同的修饰符。
例如,以下方法会在编码期间引发异常:
private String getField(); public String setField(String x);
如何修复“org.bson.codecs.configuration.CodecConfigurationException:找不到 X 类的编解码器”?
此异常意味着您必须为该类注册一个编解码器,因为目前没有。
如何为特定 POJO 类指定collection名称?有注释吗?
没有注释。 我们建议在类中添加静态字符串,如下所示:
public class Person { public static final String COLLECTION_NAME = "people"; }
以下代码段指定特定 POJO 类的collection名称:
database.getCollection(Person.COLLECTION_NAME, Person.class);
Legacy 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
类来设置写关注(write concern):
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 迁移页面。
支持
如果您无法在此找到问题的答案,请尝试问题和帮助部分中列出的论坛和支持渠道。