Spring认证中国教育管理中心-Spring Data MongoDB教程二

原标题: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"); } }

Spring认证中国教育管理中心-Spring Data MongoDB教程二

粗体代码突出显示了
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)));
  	    });
  }
}

Spring认证中国教育管理中心-Spring Data MongoDB教程二

为了在基于 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>

Spring认证中国教育管理中心-Spring Data MongoDB教程二

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 + "]";
  }

}

Spring认证中国教育管理中心-Spring Data MongoDB教程二

给定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);
  }
}

Spring认证中国教育管理中心-Spring Data MongoDB教程二

前面的示例将产生以下日志输出(包括来自 的调试消息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]

Spring认证中国教育管理中心-Spring Data MongoDB教程二

MongoConverter通过识别(通过约定)属性名称String,导致ObjectId存储在数据库中的a和 an之间进行隐式转换Id。

前面的示例旨在展示保存、更新和删除操作的使用,MongoTemplate而不是展示复杂的映射功能。

前面示例中使用的查询语法在“查询文档”部分有更详细的解释。

11.5.1.如何_id在映射层中处理字段

MongoDB 要求您有一个_id包含所有文档的字段。如果您不提供,驱动程序将分配ObjectId一个生成的值。当您使用 时MappingMongoConverter,某些规则控制 Java 类中的属性如何映射到此_id字段:

  1. 用@Id( org.springframework.data.annotation.Id)注释的属性或字段映射到该_id字段。
  2. 没有注释但已命名的属性或字段id映射到该_id字段。

下面概述了_id在使用MappingMongoConverter(默认为MongoTemplate)时对映射到文档字段的属性进行的类型转换(如果有)。

  1. 如果可能,在 Java 类中id声明为 a的属性或字段通过使用 SpringString转换为并存储为 an 。有效的转换规则委托给 MongoDB Java 驱动程序。如果无法转换为,则该值将作为字符串存储在数据库中。ObjectIdConverter<String, ObjectId>ObjectId
  2. 使用 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; 
}

Spring认证中国教育管理中心-Spring Data MongoDB教程二

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认证中国教育管理中心-Spring Data MongoDB教程二

Spring Data MongoDB 将类型信息存储为实际根类以及嵌套类型的最后一个字段(因为它是复杂的并且是 的子类型Contact)。因此,如果您现在使用mongoTemplate.findAll(Object.class, "sample"),您可以发现存储的文档是一个Sample实例。你还可以发现 value 属性实际上是一个Person.

内容来源:Spring中国教育管理中心(Spring认证)

Spring认证中国教育管理中心-Spring Data MongoDB教程二

2021年2月,VMware公司正式与北京中科卓望网络科技有限公司(以下简称:中科卓望)达成战略合作,授予其 Spring 中国教育管理中心,携手 VMware 全球最新 Spring技术和认证体系,帮助中国院校构建专业教学内容,全面赋能未来开发人。

上一篇:spring data mongodb 批量操作(bulk)通过document更新整个文档报错 Invalid BSON field name xxx


下一篇:mongoTemplate 过滤查询出来的字段(可以把_id、class字段去掉)