Overview
在本指南中,您可以学习如何使用 Java 反应式流驱动程序来存储和检索由普通旧 Java 对象(或 POJO)建模的数据。POJO 通常用于数据封装,这是将业务逻辑与数据表示分开的做法。
提示
要学习有关 POJO 的更多信息,请参阅普通旧 Java 对象维基百科条目。
本指南介绍如何执行以下任务:
配置驱动程序,对 POJO 进行序列化和反序列化
对使用 POJO 建模的数据进行 CRUD 操作
重要
本指南使用自定义Subscriber实现,如《自定义订阅服务器实现示例》指南中所述。
示例 POJO
本指南中的示例使用 Person 和 Address POJO 类为名为 people 的示例集合中的文档建模。
Person 类存储人员的姓名、年龄和地址。此类具有以下定义:
import org.bson.types.ObjectId; public final class Person { private ObjectId id; private String name; private int age; private Address address; public Person() {} public Person(final String name, final int age, final Address address) { this.name = name; this.age = age; this.address = address; } public ObjectId getId() { return id; } public void setId(final ObjectId id) { this.id = id; } public String getName() { return name; } public void setName(final String name) { this.name = name; } public int getAge() { return age; } public void setAge(final int age) { this.age = age; } public Address getAddress() { return address; } public void setAddress(final Address address) { this.address = address; } public String toString() { return "Person{" + "id='" + id + "'" + ", name='" + name + "'" + ", age=" + age + ", address=" + address + "}"; } }
Address 类存储街道、城市和 ZIP 编码。此类具有以下定义:
public final class Address { private String street; private String city; private String zip; public Address() {} public Address(final String street, final String city, final String zip) { this.street = street; this.city = city; this.zip = zip; } public String getStreet() { return street; } public void setStreet(final String street) { this.street = street; } public String getCity() { return city; } public void setCity(final String city) { this.city = city; } public String getZip() { return zip; } public void setZip(final String zip) { this.zip = zip; } public String toString() { return "Address{" + "street='" + street + "'" + ", city='" + city + "'" + ", zip='" + zip + "'" + "}"; } }
定义 POJO 类时,请确保满足以下要求:
POJO 类不能实现接口或继承框架中的类。
放入您要存储和检索数据的所有字段,并确保它们没有标记为
static或transient。如果您按照 JavaBean 命名规范包含公共 getter 或 setter 方法,则驱动程序将在序列化或反序列化数据时调用这些方法。如果您省略公共字段的 getter 或 setter 方法,则驱动程序将直接访问或赋值这些字段。
为 POJO 配置驱动程序
在将 POJO 与 Java Reactive Streams 驱动程序一起使用之前,必须通过创建自定义 CodecRegistry 将其配置为序列化和反序列化 POJO。以下步骤展示如何创建 CodecRegistry 并将其应用于客户端、数据库或集合。
应用 CodecRegistry。
将 MongoClient、MongoDatabase 或 MongoCollection 实例配置为使用自定义 CodecRegistry。您可以通过以下方式之一设置编解码器注册表:
在
MongoClient上设置CodecRegistry:MongoClientSettings settings = MongoClientSettings.builder() .codecRegistry(pojoCodecRegistry) .build(); 在
MongoDatabase上设置CodecRegistry:MongoDatabase database = mongoClient.getDatabase("mydb").withCodecRegistry(pojoCodecRegistry); 在
MongoCollection上设置CodecRegistry:MongoCollection<org.bson.Document> rawCollection = database.getCollection("people").withCodecRegistry(pojoCodecRegistry);
执行 CRUD 操作
将驱动程序配置为使用 Person POJO 后,您可以对 POJO 建模的数据执行 CRUD 操作。
Insert Data
编解码器注册表会自动为未知类创建 POJO Codec ,使您可以开箱即用 POJO,无需额外配置。
要将单个 Person 插入到集合中,调用 insertOne() 方法并订阅结果。以下示例将名为 ada 的 Person 实例插入到 people 集合中:
Person ada = new Person("Ada Byron", 20, new Address("St James Square", "London", "W1")); collection.insertOne(ada).subscribe(new OperationSubscriber<InsertOneResult>());
要插入多个 Person 实例,调用 insertMany() 方法并传递实例列表,如以下示例所示:
List<Person> people = asList( new Person("Charles Babbage", 45, new Address("5 Devonshire Street", "London", "W11")), new Person("Alan Turing", 28, new Address("Bletchley Hall", "Bletchley Park", "MK12")), new Person("Timothy Berners-Lee", 61, new Address("Colehill", "Wimborne", null)) ); collection.insertMany(people).subscribe(new OperationSubscriber<InsertManyResult>());
查询数据
要查询集合,请使用 find() 方法。您可以将过滤器对象传递给 find() 方法,以检索符合特定条件的文档。驱动程序提供 Filters 个辅助工具方法,您可以使用这些方法创建过滤器对象。
重要
查询 POJO 时,必须查询文档字段名称,而不是 POJO 属性名称。默认情况下,它们是相同的,但可以更改驱动程序映射 POJO 属性名称的方式。
Retrieve One
要检索符合过滤器的第一个 Person 实例,请在 find() 操作的结果上调用 first() 方法。
以下示例检索具有 address.city 字段值 "Wimborne" 的第一个 Person 实例:
collection.find(eq("address.city", "Wimborne")) .first() .subscribe(new PrintToStringSubscriber<>());
Person{id='...', name='Timothy Berners-Lee', age=61, address=Address{street='Colehill', city='Wimborne', zip='null'}}
检索多个
要检索符合过滤器的所有 Person 实例,请调用 find() 方法并订阅结果。
以下示例检索每个具有大于 30 的 age 字段值的 Person 实例:
collection.find(gt("age", 30)).subscribe(new PrintToStringSubscriber<>());
Person{id='...', name='Charles Babbage', age=45, address=Address{street='5 Devonshire Street', city='London', zip='W11'}} Person{id='...', name='Timothy Berners-Lee', age=61, address=Address{street='Colehill', city='Wimborne', zip='null'}}
更新数据
要更新集合中的文档,请使用 updateOne() 和 updateMany() 方法。将以下参数传递给这些方法:
指定要更新的文档的过滤器对象。
更新指定修改的文档。要查看可用操作符的列表,请参阅 MongoDB Server 手册中的更新操作符。
更新方法返回 UpdateResult 类型,其中提供有关操作的信息,包括修改的文档数量。
updateOne
要更新与筛选器匹配的单个 Person 实例,请使用 updateOne() 方法。
以下示例通过将 age 字段值设置为 23,并将 name 字段值设置为 "Ada Lovelace",来更新命名为 "Ada Byron" 的 Person:
collection.updateOne( eq("name", "Ada Byron"), combine(set("age", 23), set("name", "Ada Lovelace")) ).subscribe(new OperationSubscriber<>());
更新多个
要更新与筛选器匹配的所有Person实例,请使用updateMany()方法。
以下示例将所有具有非空 zip 值的 Person 实例的 zip 字段值设置为 null:
collection.updateMany(not(eq("zip", null)), set("zip", null)) .subscribe(new OperationSubscriber<>());
replaceOne
要完全替换现有的 Person 实例,请使用 replaceOne() 方法。
以下示例将具有 name 字段值 "Ada Lovelace" 的 Person 实例替换为 ada 变量引用的 Person:
collection.replaceOne(eq("name", "Ada Lovelace"), ada) .subscribe(new OperationSubscriber<>());
删除数据
要从集合中删除文档,请使用 deleteOne() 和 deleteMany() 方法。传递过滤器对象以匹配要删除的文档。
删除方法返回DeleteResult类型,其中提供有关操作的信息,包括删除的文档数。
deleteOne
要删除与过滤器匹配的单个Person ,请使用deleteOne()方法。
以下示例删除一个字段值为Person address.city的"Wimborne" 实例:
collection.deleteOne(eq("address.city", "Wimborne")) .subscribe(new OperationSubscriber<>());
删除多个
要删除与过滤器匹配的所有 Person 实例,请使用 deleteMany() 方法。
Personaddress.city以下示例删除字段值为 的所有"London" 实例:
collection.deleteMany(eq("address.city", "London")) .subscribe(new OperationSubscriber<>());
更多信息
要了解本指南中提到的 CRUD 操作的更多信息,请参阅CRUD 操作部分。
API 文档
要了解有关本指南中提到的方法和类的更多信息,请参阅以下 API 文档: