当前位置:Java -> 使用Eclipse JNoSQL在Java中实现NoSQL数据库的继承

使用Eclipse JNoSQL在Java中实现NoSQL数据库的继承

NoSQL数据库为数据库管理中的数据存储和检索提供了灵活和可扩展的选择。然而,它们可能需要在面向对象编程范例方面寻求帮助,比如继承,在诸如Java之类的语言中是一个基本概念。本文探讨了处理NoSQL数据库中继承时的阻抗不匹配。

NoSQL数据库中的继承挑战

术语“阻抗不匹配”是指面向对象编程语言如Java和NoSQL数据库的表格化、基于文档或基于图的结构之间的脱节。这种不匹配特别明显的一个领域是处理继承。

在Java中,继承允许您创建一个类的层次结构,其中子类从其父类继承属性和行为。这个概念在Java编程中根深蒂固,通常用于建模现实世界的关系。然而,NoSQL数据库没有连接操作,并且继承结构需要以不同的方式处理。

映射不匹配图形

Jakarta Persistence(JPA)和继承策略

在深入研究更高级解决方案之前,值得一提的是,在Jakarta Persistence(以前称为JPA)的世界中,有模拟在关系数据库中进行继承的策略。这些策略包括:

  1. JOINED继承策略:采用这种方法,特定于子类的字段被映射到一个与父类共同字段不同的表中。在需要时,执行连接操作来实例化子类。
  2. SINGLE_TABLE继承策略:此策略使用一个代表整个类层次结构的单个表。使用鉴别器列来区分不同的子类。
  3. TABLE_PER_CLASS继承策略:层次结构中的每个具体实体类都对应于数据库中的表。

这些策略在关系数据库中运作良好,但不直接适用于NoSQL数据库,主要是因为NoSQL数据库不支持传统连接。

实时代码会话:Java SE、Eclipse JNoSQL和MongoDB

在这个实时代码会话中,我们将创建一个使用MongoDB作为我们的NoSQL数据库的Java SE项目。我们将专注于管理游戏角色,具体来说是Mario和Sonic角色,使用Eclipse JNoSQL。您可以在本地使用Docker或在云端使用MongoDB Atlas运行MongoDB。我们将从数据库设置开始,然后继续Java代码的实现。

在本地设置MongoDB

要在本地运行MongoDB,您可以使用以下命令:

docker run -d --name mongodb-instance -p 27017:27017 mongo


或者,您可以选择按照MongoDB Atlas提供的说明在云端执行它。

MongoDB数据库运行起来之后,让我们创建我们的Java项目。

创建Java项目

我们将使用Maven和maven-archetype-quickstart骨架创建一个Java SE项目。此项目将利用以下技术和依赖关系:

Maven依赖

请将以下依赖项添加到项目的pom.xml文件中:

<dependencies>
    <dependency>
        <groupId>org.jboss.weld.se</groupId>
        <artifactId>weld-se-shaded</artifactId>
        <version>${weld.se.core.version}</version>
        <scope>compile</scope>
    </dependency>
    <dependency>
        <groupId>org.eclipse</groupId>
        <artifactId>yasson</artifactId>
        <version>3.0.3</version>
        <scope>compile</scope>
    </dependency>
    <dependency>
        <groupId>io.smallrye.config</groupId>
        <artifactId>smallrye-config-core</artifactId>
        <version>3.2.1</version>
        <scope>compile</scope>
    </dependency>
    <dependency>
        <groupId>org.eclipse.microprofile.config</groupId>
        <artifactId>microprofile-config-api</artifactId>
        <version>3.0.2</version>
        <scope>compile</scope>
    </dependency>
    <dependency>
        <groupId>org.eclipse.jnosql.databases</groupId>
        <artifactId>jnosql-mongodb</artifactId>
        <version>${jnosql.version}</version>
    </dependency>
    <dependency>
        <groupId>net.datafaker</groupId>
        <artifactId>datafaker</artifactId>
        <version>2.0.2</version>
    </dependency>
</dependencies>


确保用您打算使用的Eclipse JNoSQL的适当版本替换${jnosql.version}

在下一节中,我们将继续实现我们的Java代码。

实现我们的Java代码

我们的GameCharacter类将作为所有游戏角色的父类,并将保存它们之间共享的公共属性。我们将使用继承和鉴别器列来区分Sonic和Mario的角色。这是GameCharacter类的初始定义:

@Entity
@DiscriminatorColumn("type")
@Inheritance
public abstract class GameCharacter {

    @Id
    @Convert(UUIDConverter.class)
    protected UUID id;

    @Column
    protected String character;

    @Column
    protected String game;

    public abstract GameType getType();

}


在这段代码中:

  • 我们使用@Entity注释类来指示它是我们MongoDB数据库中的持久化实体。
  • 我们使用@DiscriminatorColumn("type")来指定将使用名为“type”的鉴别器列来区分子类。
  • @Inheritance表示这个类是继承层次结构的一部分。

GameCharacter类具有唯一标识符(id),角色名(character)和游戏名(game)的属性,以及一个抽象方法getType(),其子类将实现以指定角色类型。

特化类:Sonic和Mario

现在,让我们为Sonic和Mario实体创建特化类。这些类将扩展GameCharacter类,并提供特定于每种角色类型的附加属性。我们将使用@DiscriminatorValue为每个子类定义“type”鉴别器列可以采用的值。

@Entity
@DiscriminatorValue("SONIC")
public class Sonic extends GameCharacter {

    @Column
    private String zone;

    @Override
    public GameType getType() {
        return GameType.SONIC;
    }
}


在Sonic类中:

  • 我们使用@Entity进行注释来表示这是一个持久化实体。
  • @DiscriminatorValue("SONIC")指定“type”鉴别器列的值为“SONIC”,表示Sonic实体的值为“SONIC”
  • 我们添加了一个特定于Sonic角色的属性。
  • getType()方法返回GameType.SONIC,表明这是一个Sonic角色。
@Entity
@DiscriminatorValue("MARIO")
public class Mario extends GameCharacter {

    @Column
    private String locations;

    @Override
    public GameType getType() {
        return GameType.MARIO;
    }
}


类似地,在Mario类中:

  • 我们使用@Entity进行注释来表示这是一个持久化实体。
  • @DiscriminatorValue("MARIO")指定“type”鉴别器列的值为“MARIO”,表示Mario实体的值为“MARIO”
  • 我们添加了一个特定于Mario角色的属性locations
  • getType()方法返回GameType.MARIO,表明这是一个Mario角色。

采用这种建模方法,您可以通过鉴别器列“type”轻松区分MongoDB数据库中的Sonic和Mario角色。

我们将使用Eclipse JNoSQL创建我们的第一个与MongoDB集成的数据库。为了简化,我们将使用Data Faker库生成数据。我们的Java应用程序将把Mario和Sonic角色插入到数据库中,并执行基本操作。

应用代码

以下是生成并将数据插入MongoDB数据库的主要应用程序代码:

public class App {

    public static void main(String[] args) {
        try (SeContainer container = SeContainerInitializer.newInstance().initialize()) {
            DocumentTemplate template = container.select(DocumentTemplate.class).get();
            DataFaker faker = new DataFaker();

            Mario mario = Mario.of(faker.generateMarioData());
            Sonic sonic = Sonic.of(faker.generateSonicData());

            // Insert Mario and Sonic characters into the database
            template.insert(List.of(mario, sonic));

            // Count the total number of GameCharacter documents
            long count = template.count(GameCharacter.class);
            System.out.println("Total of GameCharacter: " + count);

            // Find all Mario characters in the database
            List<Mario> marioCharacters = template.select(Mario.class).getResultList();
            System.out.println("Find all Mario characters: " + marioCharacters);

            // Find all Sonic characters in the database
            List<Sonic> sonicCharacters = template.select(Sonic.class).getResultList();
            System.out.println("Find all Sonic characters: " + sonicCharacters);
        }
    }
}


在这段代码中:

  • 我们使用SeContainer管理CDI容器,并从Eclipse JNoSQL初始化DocumentTemplate
  • 我们使用DataFaker类生成的数据创建Mario和Sonic角色的实例。
  • 我们使用template.insert()方法将这些角色插入到MongoDB数据库中。
  • 我们计算数据库中GameCharacter文档的总数。
  • 我们检索并显示数据库中所有Mario和Sonic角色。

结果数据库结构

运行此代码后,您将看到您的MongoDB数据库中类似以下结构的数据:

[
  {
    "_id": "39b8901c-669c-49db-ac42-c1cabdcbb6ed",
    "character": "Bowser",
    "game": "Super Mario Bros.",
    "locations": "Mount Volbono",
    "type": "MARIO"
  },
  {
    "_id": "f60e1ada-bfd9-4da7-8228-6a7f870e3dc8",
    "character": "Perfect Chaos",
    "game": "Sonic Rivals 2",
    "type": "SONIC",
    "zone": "Emerald Hill Zone"
  }
]


如数据库结构所示,每个文档包含唯一标识符(_id)、角色名称(character)、游戏名称(game),以及用于区分Mario和Sonic角色的鉴别器列type。根据生成的数据,您将在MongoDB数据库中看到更多角色。

此集成演示了如何使用Eclipse JNoSQL和MongoDB插入、计数和检索游戏角色。您可以扩展并增强此应用程序,根据需要管理和操作游戏角色数据。

我们将使用Eclipse JNoSQL创建用于管理游戏角色的存储库。我们将为一般游戏角色创建一个Console存储库,以及专门用于Sonic角色的SonicRepository。这些存储库将允许我们与数据库进行交互,并轻松执行各种操作。

让我们定义用于我们的游戏角色的存储库。

Console存储库

@Repository
public interface Console extends PageableRepository<GameCharacter, UUID> {
}


Console存储库扩展了PageableRepository,用于一般游戏角色。它提供了常见的CRUD操作和分页支持。

Sonic存储库

@Repository
public interface SonicRepository extends PageableRepository<Sonic, UUID> {
}


SonicRepository扩展了PageableRepository,专门设计用于Sonic角色。它从父存储库继承了常见的CRUD操作和分页支持。

主应用程序代码

现在,让我们修改我们的主应用程序代码以使用这些存储库。

对于Console存储库

public static void main(String[] args) {
    Faker faker = new Faker();
    try (SeContainer container = SeContainerInitializer.newInstance().initialize()) {
        Console repository = container.select(Console.class).get();
        for (int index = 0; index < 5; index++) {
            Mario mario = Mario.of(faker);
            Sonic sonic = Sonic.of(faker);
            repository.saveAll(List.of(mario, sonic));
        }

        long count = repository.count();
        System.out.println("Total of GameCharacter: " + count);

        System.out.println("Find all game characters: " + repository.findAll().toList());
    }
    System.exit(0);
}


在此代码中,我们使用Console存储库保存Mario和Sonic角色,演示了其管理一般游戏角色的能力。

对于Sonic存储库

public static void main(String[] args) {
    Faker faker = new Faker();
    try (SeContainer container = SeContainerInitializer.newInstance().initialize()) {
        SonicRepository repository = container.select(SonicRepository.class).get();
        for (int index = 0; index < 5; index++) {
            Sonic sonic = Sonic.of(faker);
            repository.save(sonic);
        }

        long count = repository.count();
        System.out.println("Total of Sonic characters: " + count);

        System.out.println("Find all Sonic characters: " + repository.findAll().toList());
    }
    System.exit(0);
}


此代码使用SonicRepository专门保存Sonic角色,展示了如何使用专门用于特定角色类型的存储库。

有了这些存储库,您可以轻松管理、查询和筛选基于它们的类型的游戏角色,简化了代码并使其更有组织性。

结论

在本文中,我们探讨了使用Eclipse JNoSQL框架将MongoDB与Java无缝集成,实现游戏角色的高效管理。我们深入探讨了对游戏角色进行建模的复杂性,在NoSQL数据库中处理继承相关的挑战,并同时与Java的面向对象原则保持兼容。通过使用鉴别器列,我们可以对角色进行分类并将其存储在MongoDB数据库中,从而创建了一个结构良好且可扩展的解决方案。

通过我们的Java应用程序,我们展示了如何使用Data Faker库生成示例游戏角色数据,并有效地将其插入MongoDB中。我们执行了一些基本操作,比如计算游戏角色的数量和检索特定角色类型。此外,我们介绍了Eclipse JNoSQL中的存储库的概念,展示了它们在简化数据管理和基于角色类型的集中查询中的价值。本文为利用Eclipse JNoSQL和MongoDB的威力构建更易于管理和操作多样数据集的Java应用程序中的NoSQL数据库交互提供了坚实的基础。

推荐阅读: 38.当线程1进入到一个对象的synchronized方法A后,线程2是否可以进入到此对象的synchronized方法B?

本文链接: 使用Eclipse JNoSQL在Java中实现NoSQL数据库的继承