原标题:Spring Data MongoDB参考文档二(内容来源:Spring中国教育管理中心)
11.3.3.MongoDatabaseFactory 接口
虽然
com.mongodb.client.MongoClient是 MongoDB 驱动程序 API 的入口点,但连接到特定的 MongoDB 数据库实例需要其他信息,例如数据库名称和可选的用户名和密码。使用该信息,您可以获得一个com.mongodb.client.MongoDatabase对象并访问特定 MongoDB 数据库实例的所有功能。Spring 提供了org.springframework.data.mongodb.core.MongoDatabaseFactory如下清单所示的接口来引导连接到数据库:
public interface MongoDatabaseFactory { MongoDatabase getDatabase() throws DataAccessException; MongoDatabase getDatabase(String dbName) throws DataAccessException; }
以下部分展示了如何使用带有基于 Java 或基于 XML 的元数据的容器来配置MongoDatabaseFactory接口的实例。反过来,您可以使用该MongoDatabaseFactory实例来配置MongoTemplate.
您可以在标准 Java 代码中使用它们,而不是使用 IoC 容器来创建 MongoTemplate 的实例,如下所示:
public class MongoApp { private static final Log log = LogFactory.getLog(MongoApp.class); public static void main(String[] args) throws Exception { MongoOperations mongoOps = new MongoTemplate(new SimpleMongoClientDatabaseFactory(MongoClients.create(), "database")); mongoOps.insert(new Person("Joe", 34)); log.info(mongoOps.findOne(new Query(where("name").is("Joe")), Person.class)); mongoOps.dropCollection("person"); } }
粗体代码突出显示了
SimpleMongoClientDbFactory和入门部分中显示的清单之间的唯一区别。
SimpleMongoClientDbFactory在选择com.mongodb.client.MongoClient作为选择的入口点时 使用。
11.3.4.MongoDatabaseFactory使用基于 Java 的元数据注册实例
要向MongoDatabaseFactory容器注册实例,您编写的代码与前面代码清单中突出显示的非常相似。以下清单显示了一个简单的示例:
@Configuration
public class MongoConfiguration {
public @Bean MongoDatabaseFactory mongoDatabaseFactory() {
return new SimpleMongoClientDatabaseFactory(MongoClients.create(), "database");
}
}
MongoDB 服务器第 3 代在连接到数据库时更改了身份验证模型。因此,一些可用于身份验证的配置选项不再有效。您应该使用MongoClient-specific 选项来设置凭据MongoCredential以提供身份验证数据,如以下示例所示:
@Configuration
public class ApplicationContextEventTestsAppConfig extends AbstractMongoClientConfiguration {
@Override
public String getDatabaseName() {
return "database";
}
@Override
protected void configureClientSettings(Builder builder) {
builder
.credential(MongoCredential.createCredential("name", "db", "pwd".toCharArray()))
.applyToClusterSettings(settings -> {
settings.hosts(singletonList(new ServerAddress("127.0.0.1", 27017)));
});
}
}
为了在基于 XML 的配置中使用身份验证,请使用元素credential上的属性<mongo-client>。
在基于XML的配置中使用的用户名和密码凭证必须URL编码时这些包含保留的字符,例如:,%,@,或,。以下示例显示了编码凭据: m0ng0@dmin:mo_res:bw6},Qsdxx@admin@database→
m0ng0%40dmin:mo_res%3Abw6%7D%2CQsdxx%40admin@database 有关更多详细信息,请参阅RFC 3986 的第 2.2 节。
11.3.5.MongoDatabaseFactory使用基于 XML 的元数据注册实例
该mongo命名空间提供了一个方便的方法来创建一个
SimpleMongoClientDbFactory,因为相比于使用<beans/>名称空间,如显示在下面的例子:
<mongo:db-factory dbname="database">
如果您需要在
com.mongodb.client.MongoClient用于创建的实例上配置其他选项SimpleMongoClientDbFactory,您可以使用mongo-ref以下示例中所示的属性来引用现有 bean 。为了显示另一种常见的使用模式,以下清单显示了属性占位符的使用,它允许您参数化配置和创建MongoTemplate:
<context:property-placeholder location="classpath:/com/myapp/mongodb/config/mongo.properties"/>
<mongo:mongo-client host="${mongo.host}" port="${mongo.port}">
<mongo:client-settings connection-pool-max-connection-life-time="${mongo.pool-max-life-time}"
connection-pool-min-size="${mongo.pool-min-size}"
connection-pool-max-size="${mongo.pool-max-size}"
connection-pool-maintenance-frequency="10"
connection-pool-maintenance-initial-delay="11"
connection-pool-max-connection-idle-time="30"
connection-pool-max-wait-time="15" />
</mongo:mongo-client>
<mongo:db-factory dbname="database" mongo-ref="mongoClient"/>
<bean id="anotherMongoTemplate" class="org.springframework.data.mongodb.core.MongoTemplate">
<constructor-arg name="mongoDbFactory" ref="mongoDbFactory"/>
</bean>
11.4.简介MongoTemplate
该MongoTemplate班,地处
org.springframework.data.mongodb.core包,是*级的Spring的MongoDB的支持,并提供了与数据库交互的丰富的功能集。该模板提供了创建、更新、删除和查询 MongoDB 文档的便捷操作,并提供了域对象和 MongoDB 文档之间的映射。
配置后,MongoTemplate是线程安全的,可以在多个实例中重复使用。
MongoDB 文档和域类之间的映射是通过委托给MongoConverter接口的实现来完成的。Spring 提供了MappingMongoConverter,但您也可以编写自己的转换器。有关更多详细信息,请参阅“自定义转换 - 覆盖默认映射”。
本MongoTemplate类实现了接口MongoOperations。上的方法尽可能MongoOperations以 MongoDB 驱动程序Collection对象上可用的方法命名,以使使用驱动程序 API 的现有 MongoDB 开发人员熟悉该 API。例如,你可以找到方法,如find,findAndModify,findAndReplace,findOne,insert,remove,save,update,和updateMulti。设计目标是尽可能轻松地在基本 MongoDB 驱动程序和MongoOperations. 两个 API 之间的主要区别是MongoOperations可以传递域对象而不是Document. 此外,MongoOperations有流利的API Query,Criteria以及Update操作,而不是填充一个Document 指定这些操作的参数。
引用MongoTemplate实例操作的首选方法是通过其接口MongoOperations.
使用的默认转换器实现MongoTemplate是MappingMongoConverter. 虽然MappingMongoConverter可以使用附加元数据来指定对象到文档的映射,但它也可以通过使用一些映射 ID 和集合名称的约定来转换不包含附加元数据的对象。这些约定以及映射注解的使用在“映射”一章中进行了解释。
另一个核心功能MongoTemplate是将 MongoDB Java 驱动程序抛出的异常转换为 Spring 的可移植数据访问异常层次结构。有关更多信息,请参阅“异常翻译”。
MongoTemplate提供了许多方便的方法来帮助您轻松执行常见任务。但是,如果您需要直接访问 MongoDB 驱动程序 API,则可以使用多种Execute回调方法之一。该execute回调给你到任何一个参考
com.mongodb.client.MongoCollection或com.mongodb.client.MongoDatabase对象。有关更多信息,请参阅“执行回调”部分。
下一节包含一个示例,说明如何MongoTemplate在 Spring 容器的上下文中使用 。
11.4.1.实例化MongoTemplate
您可以使用 Java 创建和注册 的实例MongoTemplate,如以下示例所示:
示例 61. 注册一个
com.mongodb.client.MongoClient对象并启用 Spring 的异常转换支持
@Configuration
public class AppConfig {
public @Bean MongoClient mongoClient() {
return MongoClients.create("mongodb://localhost:27017");
}
public @Bean MongoTemplate mongoTemplate() {
return new MongoTemplate(mongoClient(), "mydatabase");
}
}
有几个重载的构造函数MongoTemplate:
- MongoTemplate(MongoClient mongo, String databaseName):采用MongoClient对象和默认数据库名称进行操作。
- MongoTemplate(MongoDatabaseFactory mongoDbFactory):采用封装了MongoClient对象、数据库名称、用户名和密码的 MongoDbFactory 对象。
- MongoTemplate(MongoDatabaseFactory mongoDbFactory, MongoConverter mongoConverter): 添加一个MongoConverter用于映射。
您还可以使用 Spring 的 XML <beans/> 模式配置 MongoTemplate,如以下示例所示:
<mongo:mongo-client host="localhost" port="27017"/>
<bean id="mongoTemplate" class="org.springframework.data.mongodb.core.MongoTemplate">
<constructor-arg ref="mongoClient"/>
<constructor-arg name="databaseName" value="geospatial"/>
</bean>
其他创建时可能会想设置可选属性MongoTemplate是默认WriteResultCheckingPolicy,WriteConcern和ReadPreference属性。
引用MongoTemplate实例操作的首选方法是通过其接口MongoOperations.
11.4.2.WriteResultChecking政策
在开发中,如果com.mongodb.WriteResult从任何 MongoDB 操作返回的包含错误,记录或抛出异常是很方便的。在开发过程中忘记这样做是很常见的,然后最终得到一个看起来运行成功的应用程序,而实际上,数据库并没有按照您的预期进行修改。您可以将 的WriteResultChecking属性设置为MongoTemplate以下值之一:EXCEPTION或NONE,分别用于抛出Exception或不执行任何操作。默认值是使用 的WriteResultChecking值NONE。
11.4.3.WriteConcern
如果尚未通过更高级别的驱动程序指定(例如
com.mongodb.client.MongoClient),则可以设置用于写操作的com.mongodb.WriteConcern属性MongoTemplate。如果WriteConcern未设置该属性,则默认为 MongoDB 驱动程序的 DB 或 Collection 设置中的设置。
11.4.4.WriteConcernResolver
对于更高级的情况,您希望WriteConcern在每个操作的基础上设置不同的值(用于删除、更新、插入和保存操作),WriteConcernResolver可以在MongoTemplate. 由于MongoTemplate用于持久化 POJO,因此WriteConcernResolver您可以创建一个策略,将特定的 POJO 类映射到一个WriteConcern值。以下清单显示了WriteConcernResolver界面:
public interface WriteConcernResolver {
WriteConcern resolve(MongoAction action);
}
您可以使用MongoAction参数来确定WriteConcern值或使用模板本身的值作为默认值。MongoAction包含集合名称被写入时,java.lang.Class所述POJO,转换后的Document,操作(REMOVE,UPDATE,INSERT,INSERT_LIST,或SAVE),和其他一些条上下文信息。以下示例显示了两组获得不同WriteConcern设置的类:
private class MyAppWriteConcernResolver implements WriteConcernResolver {
public WriteConcern resolve(MongoAction action) {
if (action.getEntityClass().getSimpleName().contains("Audit")) {
return WriteConcern.NONE;
} else if (action.getEntityClass().getSimpleName().contains("Metadata")) {
return WriteConcern.JOURNAL_SAFE;
}
return action.getDefaultWriteConcern();
}
}
11.5.保存、更新和删除文档
MongoTemplate 允许您保存、更新和删除域对象并将这些对象映射到存储在 MongoDB 中的文档。
考虑以下类:
public class Person {
private String id;
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public String getId() {
return id;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
@Override
public String toString() {
return "Person [id=" + id + ", name=" + name + ", age=" + age + "]";
}
}
给定Person前面示例中的类,您可以保存、更新和删除对象,如以下示例所示:
MongoOperations是MongoTemplate实现的接口。
package org.spring.example;
import static org.springframework.data.mongodb.core.query.Criteria.where;
import static org.springframework.data.mongodb.core.query.Update.update;
import static org.springframework.data.mongodb.core.query.Query.query;
import java.util.List;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.data.mongodb.core.MongoOperations;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.SimpleMongoClientDbFactory;
import com.mongodb.client.MongoClients;
public class MongoApp {
private static final Log log = LogFactory.getLog(MongoApp.class);
public static void main(String[] args) {
MongoOperations mongoOps = new MongoTemplate(new SimpleMongoClientDbFactory(MongoClients.create(), "database"));
Person p = new Person("Joe", 34);
// Insert is used to initially store the object into the database.
mongoOps.insert(p);
log.info("Insert: " + p);
// Find
p = mongoOps.findById(p.getId(), Person.class);
log.info("Found: " + p);
// Update
mongoOps.updateFirst(query(where("name").is("Joe")), update("age", 35), Person.class);
p = mongoOps.findOne(query(where("name").is("Joe")), Person.class);
log.info("Updated: " + p);
// Delete
mongoOps.remove(p);
// Check that deletion worked
List<Person> people = mongoOps.findAll(Person.class);
log.info("Number of people = : " + people.size());
mongoOps.dropCollection(Person.class);
}
}
前面的示例将产生以下日志输出(包括来自 的调试消息MongoTemplate):
DEBUG apping.MongoPersistentEntityIndexCreator: 80 - Analyzing class class org.spring.example.Person for index information.
DEBUG work.data.mongodb.core.MongoTemplate: 632 - insert Document containing fields: [_class, age, name] in collection: person
INFO org.spring.example.MongoApp: 30 - Insert: Person [id=4ddc6e784ce5b1eba3ceaf5c, name=Joe, age=34]
DEBUG work.data.mongodb.core.MongoTemplate:1246 - findOne using query: { "_id" : { "$oid" : "4ddc6e784ce5b1eba3ceaf5c"}} in db.collection: database.person
INFO org.spring.example.MongoApp: 34 - Found: Person [id=4ddc6e784ce5b1eba3ceaf5c, name=Joe, age=34]
DEBUG work.data.mongodb.core.MongoTemplate: 778 - calling update using query: { "name" : "Joe"} and update: { "$set" : { "age" : 35}} in collection: person
DEBUG work.data.mongodb.core.MongoTemplate:1246 - findOne using query: { "name" : "Joe"} in db.collection: database.person
INFO org.spring.example.MongoApp: 39 - Updated: Person [id=4ddc6e784ce5b1eba3ceaf5c, name=Joe, age=35]
DEBUG work.data.mongodb.core.MongoTemplate: 823 - remove using query: { "id" : "4ddc6e784ce5b1eba3ceaf5c"} in collection: person
INFO org.spring.example.MongoApp: 46 - Number of people = : 0
DEBUG work.data.mongodb.core.MongoTemplate: 376 - Dropped collection [database.person]
MongoConverter通过识别(通过约定)属性名称String,导致ObjectId存储在数据库中的a和 an之间进行隐式转换Id。
前面的示例旨在展示保存、更新和删除操作的使用,MongoTemplate而不是展示复杂的映射功能。
前面示例中使用的查询语法在“查询文档”部分有更详细的解释。
11.5.1.如何_id在映射层中处理字段
MongoDB 要求您有一个_id包含所有文档的字段。如果您不提供,驱动程序将分配ObjectId一个生成的值。当您使用 时MappingMongoConverter,某些规则控制 Java 类中的属性如何映射到此_id字段:
- 用@Id( org.springframework.data.annotation.Id)注释的属性或字段映射到该_id字段。
- 没有注释但已命名的属性或字段id映射到该_id字段。
下面概述了_id在使用MappingMongoConverter(默认为MongoTemplate)时对映射到文档字段的属性进行的类型转换(如果有)。
- 如果可能,在 Java 类中id声明为 a的属性或字段通过使用 SpringString转换为并存储为 an 。有效的转换规则委托给 MongoDB Java 驱动程序。如果无法转换为,则该值将作为字符串存储在数据库中。ObjectIdConverter<String, ObjectId>ObjectId
- 使用 Spring将在 Java 类中id声明的属性或字段BigInteger转换为 并存储为。ObjectIdConverter<BigInteger, ObjectId>
如果 Java 类中不存在先前规则集中指定的字段或属性_id,则驱动程序会生成一个隐式文件,但不会映射到 Java 类的属性或字段。
查询和更新时,MongoTemplate使用与上述规则对应的转换器来保存文档,以便查询中使用的字段名称和类型可以匹配域类中的内容。
某些环境需要自定义方法来映射Id值,例如存储在 MongoDB 中的未通过 Spring Data 映射层运行的数据。文档可以包含_id可以表示为ObjectId或 的值String。从存储读取文档回域类型工作正常。id由于隐式ObjectId转换,通过它们查询文档可能很麻烦。因此无法以这种方式检索文档。对于这些情况,@MongoId提供对实际 id 映射尝试的更多控制。
例 62.@MongoId映射
public class PlainStringId {
@MongoId String id;
}
public class PlainObjectId {
@MongoId ObjectId id;
}
public class StringToObjectId {
@MongoId(FieldType.OBJECT_ID) String id;
}
11.5.2.类型映射
MongoDB 集合可以包含表示各种类型实例的文档。如果您存储类的层次结构或具有具有 type 属性的类,则此功能非常有用Object。在后一种情况下,该属性中保存的值必须是在检索对象时正确读入。因此,我们需要一种机制来将类型信息与实际文档一起存储。
为了实现这一点,它MappingMongoConverter使用了一个MongoTypeMapper抽象DefaultMongoTypeMapper作为其主要实现。它的默认行为是_class在文档内部存储完全限定的类名。为*文档以及每个值(如果它是复杂类型)编写类型提示和声明的属性类型的子类型。以下示例(末尾带有 JSON 表示)显示了映射的工作原理:
示例 63. 类型映射
public class Sample {
Contact value;
}
public abstract class Contact { … }
public class Person extends Contact { … }
Sample sample = new Sample();
sample.value = new Person();
mongoTemplate.save(sample);
{
"value" : { "_class" : "com.acme.Person" },
"_class" : "com.acme.Sample"
}
Spring Data MongoDB 将类型信息存储为实际根类以及嵌套类型的最后一个字段(因为它是复杂的并且是 的子类型Contact)。因此,如果您现在使用mongoTemplate.findAll(Object.class, "sample"),您可以发现存储的文档是一个Sample实例。你还可以发现 value 属性实际上是一个Person.
内容来源:Spring中国教育管理中心(Spring认证)
2021年2月,VMware公司正式与北京中科卓望网络科技有限公司(以下简称:中科卓望)达成战略合作,授予其 Spring 中国教育管理中心,携手 VMware 全球最新 Spring技术和认证体系,帮助中国院校构建专业教学内容,全面赋能未来开发人。