Overview
在本教程中,您可以学习;了解如何将 Spring Data MongoDB 与Java驾驶员结合使用,以便在 Spring Boot应用程序中执行高性能批量插入。
Spring Data MongoDB
Spring Data MongoDB是适用于MongoDB的官方 Spring Data对象文档映射器 (ODM)。它允许您使用普通的旧Java对象 (POJO) 和存储库抽象与MongoDB进行交互。它支持MongoDB特有的功能,如动态查询、索引和嵌套文档映射,同时减少样板代码,如手动 find() 和 update() 调用。
Spring Boot
Spring Boot 是一个构建在 Spring 框架之上的框架。它添加了自动配置、默认值和生产就绪功能,以简化构建基于 Spring 的Java应用程序,包括与 Spring Data MongoDB 的集成。有关更多信息,请参阅 Spring Boot 文档。
依赖注入
依赖注入 (DI) 是 Spring 框架的核心原则。它允许 Spring容器创建和管理称为 Bean 的对象,然后将它们注入到使用它们的其他 Bean 中。这与典型的面向对象开发不同,在典型的面向对象开发中,类负责初始化和构造它们使用的对象。
Spring Data BulkOperations 接口
BulkOperations 是一个 Spring Data MongoDB接口,其中包含可应用于数据库的写入操作列表。它可以处理以下操作的任意组合,这些操作映射到类似的MongoDB Java驱动程序操作:
insertupdateOneupdateManyreplaceOnedeleteOnedeleteManyupsert
BulkOperation 可以是有序的,也可以是无序的。有序批量操作按顺序运行操作,如果检测到错误,则返回并附带错误代码。无序操作并行运行,这意味着它们通常速度更快。但是,您必须手动检查操作过程中是否出现错误。
有关批量操作的更多信息,请参阅以下资源:
Spring 框架API文档中的 BulkOperations
Tutorial
您可以在 SpringDataBulkInsert示例项目GitHub存储库中找到本教程的完整示例应用。
先决条件
在开始本教程之前,请确保已安装并设立以下组件:
添加依赖项
确保您使用的 Spring Data MongoDB版本与您正在使用的MongoDB Java驱动程序和Java版本兼容。有关兼容性规范,请参阅 Spring Data MongoDB文档的“要求”页面和本指南的“兼容性”页面。
注意
如果您使用 Spring Initializr 或 Spring Boot示例项目的克隆来创建项目,则已考虑版本控制兼容性,并且 spring-boot-starter-data-mongodb组件已包含在pom.xml 文件中。
将以下依赖项添加到您的 pom.xml文件中:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-mongodb</artifactId> <version>3.2.5 </version> </dependency> <dependency> <groupId>net.datafaker</groupId> <artifactId>datafaker</artifactId> <version>2.4.3</version> </dependency>
datafaker 依赖项用于生成大量 Product 对象以在批量写入操作中使用。
配置您的 MongoClient
MongoConfig类包含MongoClient 对象的配置,该对象将允许 Spring Data框架与MongoDB Server交互,并设置其他配置选项。有关配置选项的更多信息,请参阅本指南的“指定连接选项”页面。
此应用程序对类使用 @Configuration 注解,对方法使用 @Bean 注解,对参数转换使用 @Value 注解。这些注解允许 Spring 控制反转 (IoC)容器管理对象。有关这些注解的详细说明,请参阅 Spring Data框架指南的以下部分:
@Configuration和@Bean注解:基于 Java 的容器配置@Value注解:使用 @Value
创建 MongoConfig.java文件并添加以下配置和模板类以设立MongoDB连接:
package com.mongodb.examples.springdatabulkinsert; import com.mongodb.ConnectionString; import com.mongodb.MongoClientSettings; import com.mongodb.client.MongoClient; import com.mongodb.client.MongoClients; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.mongodb.core.MongoTemplate; public class MongoConfig { private String uri; private String databaseName; public MongoClient mongoClient() { ConnectionString connectionString = new ConnectionString(uri); MongoClientSettings mongoClientSettings = MongoClientSettings.builder() .applyConnectionString(connectionString) .build(); return MongoClients.create(mongoClientSettings); } public MongoTemplate mongoTemplate() throws Exception { return new MongoTemplate(mongoClient(), databaseName); } }
注意
API与接口
此实施使用 MongoTemplate API,而不是扩展 MongoRepository 等 Spring 数据存储库接口,以允许对批量操作进行细粒度控制。
在 application.properties文件中设置连接字符串(mongodb.uri)、数据库名称 (mongodb.database) 和批量操作计数 (documentCount) 的值:
mongodb.database=bulk mongodb.uri=<connection string> documentCount=25000
本教程使用名为bulk 25的数据库,并创建要保存的,000 文档。将<connection
string> 占位符替换为Atlas部署的连接字符串。有关更多信息,请参阅本指南的“创建连接字符串”部分。
将对象映射到文档
将类映射到集合允许 Spring IoC容器将对象存储为MongoDB文档。您可以使用@Document 注解来指定类映射到哪个集合。有关将对象映射到MongoDB文档的更多信息,请参阅 Spring Data MongoDB文档的映射注解概述部分。
@Id以下代码中的 注解表示对象id 字段映射到文档_id 字段,该字段用作MongoDB文档中的唯一标识符。您可以选择任何类型(数组除外)的任何字段作为唯一标识符。有关更多信息,请参阅 Spring Data MongoDB文档的映射层中如何处理_id字段部分。
使用以下代码创建 Product.java文件,以定义 Product 类并将其映射到 products集合:
public class Product { private static final Logger LOG = LoggerFactory.getLogger(Product.class); private String id; private String name; private int qty; private double price; private Date available; private Date unavailable; private String skuId; public Product(String name, int qty, double price, Date available, Date unavailable, String skuId) { this.name = name; this.qty = qty; this.price = price; this.available = available; this.unavailable = unavailable; this.skuId = skuId; } public static List<Product> randomProducts(int count) { Faker faker = new Faker(); Random rand = new Random(); List<Product> retProds = new ArrayList<>(count); for (int i = 0; i < count; ++i) { Product product = new Product(faker.animal().name(), 1 + rand.nextInt(998), 10.0 + rand.nextInt(9999), new Date(), new Date(), faker.idNumber().valid()); retProds.add(product); } return retProds; } // Getters and setters }
Product 类包含一个生成 Product 对象大量的静态方法。您还可以为字段定义 getter 和 setter。
定义存储库来存储您的产品
ProductRepository对象将管理Product 对象的集合。您的ProductRepository 对象必须注入MongoTemplate MongoConfig类中生成的 bean。通过将@Autowired 注解与包含mongoTemplate 作为参数的构造函数一起使用,Spring容器会使用构造函数注入来注入mongoTemplate 依赖项。有关构造函数注入的更多信息,请参阅 Spring 框架文档中基于构造函数的依赖注入部分。
使用以下代码创建 ProductRepository.java文件并定义 ProductRepository 类来管理Product 对象的集合:
public class ProductRepository { private static final Logger LOG = LoggerFactory .getLogger(ProductRepository.class); private final MongoTemplate mongoTemplate; public ProductRepository(MongoTemplate mongoTemplate){ this.mongoTemplate = mongoTemplate; } public void updateProductQuantity(String name, int newQuantity) { Query query = new Query(Criteria.where("name").is(name)); Update update = new Update(); update.set("quantity", newQuantity); UpdateResult result = mongoTemplate.updateFirst(query, update, Product.class); if (result == null) LOG.error("No documents updated"); else LOG.info(result.getModifiedCount() + " document(s) updated.."); } public int bulkInsertProducts(int count) { LOG.info("Dropping collection..."); mongoTemplate.dropCollection(Product.class); LOG.info("Dropped!"); Instant start = Instant.now(); mongoTemplate.setWriteConcern(WriteConcern.W1.withJournal(true)); List<Product> productList = Product.randomProducts(count); BulkOperations bulkInsertion = mongoTemplate.bulkOps(BulkOperations.BulkMode.UNORDERED, Product.class); bulkInsertion.insert(productList); BulkWriteResult bulkWriteResult = bulkInsertion.execute(); LOG.info("Bulk insert of " + bulkWriteResult.getInsertedCount() + " documents completed in " + Duration.between(start, Instant.now()).toMillis() + " milliseconds"); return bulkWriteResult.getInsertedCount(); } }
bulkInsertProducts() 方法使用无序批量插入,可通过不保证操作顺序来提高性能。
执行批量操作
主应用程序程序类会触发 ProductRepository 生成指定数量的 Product 对象并将它们保存到MongoDB 数据库中。它使用 @Autowired 注解注入 ProductRepository,并实施日志记录。
将以下代码添加到主类以运行应用程序:
public class SpringDataBulkInsertApplication implements CommandLineRunner { private int count; private static final Logger LOG = LoggerFactory .getLogger(SpringDataBulkInsertApplication.class); private ProductRepository repository; public static void main(String[] args) { SpringApplication.run(SpringDataBulkInsertApplication.class, args); } public void run(String... args) throws Exception { repository.bulkInsertProducts(count); LOG.info("End run"); System.exit(0); } }
结论
Spring Data MongoDB为使用MongoDB提供了高级抽象。它可以通过支持自动依赖项注入来简化应用程序架构,从而无需手动进行客户端配置和复杂的查询处理。通过减少样板代码和支持面向对象的数据访问,它可以简化数据访问并促进明确的关注点分离。
更多资源
有关 Spring 和 Spring Data MongoDB框架的更多信息,请参阅以下资源:
如需支持或为MongoDB Community做出贡献,请参阅MongoDB开发者社区。