1. 概述

在这个教程中,我们将探讨Spring Data MongoDB中的@DBRef注解。我们将使用这个注解来连接MongoDB文档。此外,我们还会介绍MongoDB数据库引用的类型,并进行比较。

2. MongoDB手动数据库引用

首先讨论的是手动引用。在MongoDB中,每个文档都必须有一个_id字段。因此,我们可以依赖它来连接文档。

当使用手动引用时,我们在另一个文档中存储被引用文档的_id

当我们从第一个集合查询数据时,可以发起第二个查询来获取引用的文档。

3. Spring Data MongoDB @DBRef注解

DBRefs与手动引用类似,它们也包含引用文档的_id然而,它们在$ref字段中包含引用文档的集合,在$db字段中可选地包含其数据库。

这种做法的优点是明确了我们引用的是哪个集合。

4. 应用设置

4.1. 依赖

首先,我们需要添加所需的依赖以在Spring Boot中使用MongoDB。

让我们在pom.xml中添加spring-boot-starter-data-mongodb

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>

4.2. 配置

现在,通过在application.properties文件中添加以下配置来设置连接:

spring.data.mongodb.host=localhost
spring.data.mongodb.port=27017
spring.data.mongodb.database=person_database

运行应用以测试是否能连接到数据库。日志中应该会显示类似的消息:

Opened connection [connectionId{localValue:2, serverValue:37}] to localhost:27017

这意味着应用程序成功连接到了MongoDB。

4.3. 集合

在MongoDB中,我们使用 集合 来存储单个文档,它们类似于关系数据库中的表。

在这个例子中,我们将处理三种不同的数据类型:PersonDogCat。我们将连接人和他们的宠物。

让我们创建一个名为person_database的数据库,并在其中创建两个集合:DogCat。每个集合中插入一个文档。为了简化,两者都只包含一个属性:宠物的名字。

首先,在Dog集合中插入一个文档:

{
    _id: ObjectID("622112d71f9dac417b84227d"), 
    name: "Max"
}

然后,在Cat集合中插入一个文档:

{
    _id: ObjectID("622112781f9dac417b84227b"),
    name: "Loki"
}

接下来,创建Person集合并插入一个文档:

{
    _id: ObjectId(),
    name: "Bob",
    pets: [
        {
          "$ref": "Cat",
          "$id": "622112781f9dac417b84227b",
          "$db": ""
        },    
        {
          "$ref": "Dog",
          "$id": "622112d71f9dac417b84227d",
          "$db": ""
        }
    ]
}

我们将宠物作为数组提供。数组中的项需要遵循特定格式才能作为DBRefs使用。我们需要在$ref属性中提供集合名称,这里分别是CatDog。然后,我们包含引用文档的ID。最后,如果希望从不同数据库引用集合,可以在$db属性中提供数据库名称。

5. 使用@DBRef注解

我们可以将先前创建的集合映射到Java类,就像在处理关系数据库时一样。

为了简化,我们不会为DogCat数据类型创建单独的类。相反,我们将使用一个包含ID和名字的Pet类:

public class Pet {
    private String id;
    private String name;

    @Override 
    public String toString() {
        return "Pet [id=" + id + ", name=" + name + "]";
    }

    // standard getters and setters
}

现在,我们将创建Person类,并通过@DBRef关联到Pet类:

@Document(collection = "Person")
public class Person {

    @Id
    private String id;
    
    private String name;

    @DBRef
    private List<Pet> pets;

    @Override 
    public String toString() {
        return "Person [id=" + id + ", name=" + name + ", pets=" + pets + "]";
    }

    // standard getters and setters
}

接下来,创建一个简单的Repository,以便能够查询数据:

public interface PersonRepository extends MongoRepository<Person, String> {}

我们将通过创建一个ApplicationRunner来测试一切,当启动应用时执行MongoDB查询。我们将重写run()方法并在其中放置一条日志语句,以便查看Person集合的内容:

@Override
public void run(ApplicationArguments args) throws Exception {
    logger.info("{}", personRepository.findAll());
}

这会产生类似以下的日志输出,因为我们已经在实体类中重写了toString()方法:

com.baeldung.mongodb.dbref.DbRefTester : [Person [id=62249c5c7ffe83c50ad12700, name=Bob, pets=[Pet [id=622112781f9dac417b84227b, name=Loki], Pet [id=622112d71f9dac417b84227d, name=Max]]]]

这意味着我们成功读取并联接了来自不同集合的文档。

5.1. 引用其他数据库

@DBRef注解接受两个参数。其中一个参数是db,用于引用其他数据库中的文档。这是可选的,如果没有提供这个值,应用程序将在同一数据库中查找引用的文档。

在我们的例子中,如果CatDog位于名为pet_database的数据库中,我们需要将注解更改为@DBRef(db = "pet_database")

5.2. 懒加载

注解接受的另一个参数是lazy,这是一个布尔值,决定是否应懒加载引用的文档。默认情况下,它是false,这意味着当我们查询主实体时,引用将被积极加载。如果启用此功能,引用的文档将直到首次访问时才被加载。

6. 总结

在这篇文章中,我们比较了MongoDB的手动引用与Spring Data MongoDB的@DBRef。我们创建了三个集合,并使用这个注解连接它们。我们创建了一个Spring Boot应用,使用MongoRepository查询这些集合,并展示了相关的文档。

如往常一样,示例代码可在GitHub上找到:GitHub