NoSQL 数据库为在数据库管理中存储和检索数据提供了灵活且可扩展的选项。但是,他们可能需要面向对象编程范式的帮助,例如继承,这是 Java 等语言的基本概念。本文探讨了处理 NoSQL 数据库中的继承时的阻抗不匹配。
NoSQL 数据库中的继承挑战
术语“阻抗失配”是指面向对象的编程语言世界(如 Java)与 NoSQL 数据库的表格、面向文档或基于图形的结构之间的脱节。这种不匹配特别明显的一个领域是处理继承。
在 Java 中,继承允许您创建类的层次结构,其中子类继承其父类的属性和行为。这个概念在 Java 编程中根深蒂固,通常用于模拟现实世界的关系。但是,NoSQL 数据库没有联接,并且需要以不同的方式处理继承结构。
雅加达持久性 (JPA) 和继承策略
在深入研究更高级的解决方案之前,值得一提的是,在 Jakarta Persistence(以前称为 JPA)的世界中,有一些策略可以模拟关系数据库中的继承。这些策略包括:
JOINED 继承策略:在此方法中,特定于子类的字段将映射到与父类通用字段不同的表。在需要时,将执行联接操作来实例化子类。
SINGLE_TABLE继承策略:此策略使用表示整个类层次结构的单个表。鉴别器列用于区分不同的子类。
TABLE_PER_CLASS继承策略:层次结构中的每个具体实体类都与其在数据库中的表相对应。
这些策略在关系数据库中效果很好,但并不直接适用于 NoSQL 数据库,主要是因为 NoSQL 数据库不支持传统的连接。
实时代码会话:Java SE、Eclipse JNoSQL 和 MongoDB
在这个实时代码会话中,我们将使用 MongoDB 作为我们的 NoSQL 数据库创建一个 Java SE 项目。我们将专注于使用 Eclipse JNoSQL 管理游戏角色,特别是 Mario 和 Sonic 角色。您可以使用 Docker 在本地运行 MongoDB,也可以使用 MongoDB Atlas 在云中运行。我们将从数据库设置开始,然后继续进行 Java 代码实现。
在本地设置 MongoDB
若要在本地运行 MongoDB,可以通过以下命令使用 Docker:
docker run -d --name mongodb-instance -p 27017:27017 mongo
或者,您可以按照MongoDB Atlas提供的说明选择在云中执行它。
随着MongoDB数据库的启动和运行,让我们创建Java项目。
创建 Java 项目
我们将使用 Maven 和 maven-archetype-quickstart 原型创建一个 Java SE 项目。此项目将利用以下技术和依赖项:
雅加达CDI
雅加达JSONP
Eclipse MicroProfile(日食微配置文件)
Eclipse JNoSQL 数据库
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
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();
}
在此代码中:
我们用注释类来指示它是 MongoDB 数据库中的持久实体。
@Entity
我们用于指定名为“type”的鉴别器列将用于区分子类。
@DiscriminatorColumn("type")
@Inheritance
指示此类是继承层次结构的一部分。
该类具有唯一标识符 ()、角色名称 () 和游戏名称 () 的属性,以及一个抽象方法,其子类将实现该方法以指定角色类型。GameCharacter
id
character
game
getType()
专业课程:索尼克和马里奥
现在,让我们为 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")
指定鉴别器列将具有 Sonic 实体的值。“type”
“SONIC”
我们为 Sonic 角色添加了特定于区域的属性。
该方法返回 ,表示这是一个 Sonic 角色。
getType()
GameType.SONIC
@Entity
@DiscriminatorValue("MARIO")
public class Mario extends GameCharacter {
@Column
private String locations;
@Override
public GameType getType() {
return GameType.MARIO;
}
}
我们用注释来指示它是一个持久实体。
@Entity
@DiscriminatorValue("MARIO")
指定“type”鉴别器列将具有 Mario 实体的值。“MARIO”
我们添加了一个特定于马里奥角色的属性。
locations
该方法返回 ,表示这是一个马里奥角色。
getType()
GameType.MARIO
使用这种建模方法,您可以使用鉴别器列“类型”轻松区分 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);
}
}
}
在此代码中:
我们使用 来管理我们的 CDI 容器并从 Eclipse JNoSQL 初始化 。
SeContainer
DocumentTemplate
我们使用类生成的数据创建马里奥和索尼克角色的实例。
DataFaker
我们使用该方法将这些字符插入到 MongoDB 数据库中。
template.insert()
我们计算数据库中的文档总数。
GameCharacter
我们从数据库中检索并显示所有马里奥和索尼克角色。
生成的数据库结构
运行此代码的结果,您将在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"
}
]
如数据库结构所示,每个文档都包含唯一标识符 ()、角色名称 ()、游戏名称 () 和用于区分马里奥和索尼克角色的鉴别器列。您将在MongoDB数据库中看到更多字符,具体取决于您生成的数据。_id
character
game
type
此集成演示了如何使用 Eclipse JNoSQL 和 MongoDB 插入、计数和检索游戏角色。您可以扩展和增强此应用程序,以根据需要管理和操作您的游戏角色数据。
我们将创建用于使用 Eclipse JNoSQL 管理游戏角色的存储库。我们将有一个用于一般游戏角色的控制台存储库和一个专门用于 Sonic 角色的存储库。这些存储库将使我们能够与数据库进行交互并轻松执行各种操作。SonicRepository
让我们为游戏角色定义存储库。
控制台存储库
@Repository
public interface Console extends PageableRepository<GameCharacter, UUID> {
}
该存储库扩展并用于一般游戏角色。它提供常见的 CRUD 操作和分页支持。Console
PageableRepository
Sonic Repository
@Repository
public interface SonicRepository extends PageableRepository<Sonic, UUID> {
}
The extends but is specifically designed for Sonic characters. It inherits common CRUD operations and pagination from the parent repository.SonicRepository
PageableRepository
主要应用代码
现在,让我们修改主要应用程序代码以使用这些存储库。
对于控制台存储库
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);
}
在此代码中,我们使用控制台存储库来保存马里奥和索尼克角色,展示了它管理一般游戏角色的能力。
对于 Sonic Repository
爪哇岛
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);
}
此代码专门使用 来保存 Sonic 字符。它展示了如何使用专用于特定字符类型的存储库。SonicRepository
借助这些存储库,您可以根据游戏角色的类型轻松管理、查询和过滤游戏角色,从而简化代码并使其更有条理。
在本文中,我们探讨了使用 Eclipse JNoSQL 框架将 MongoDB 与 Java 无缝集成以实现高效的游戏角色管理。我们深入研究了游戏角色建模的复杂性,解决了与NoSQL数据库中的继承相关的挑战,同时保持了与Java面向对象原则的兼容性。通过使用鉴别器列,我们可以对字符进行分类并将它们存储在 MongoDB 数据库中,从而创建一个结构良好且可扩展的解决方案。
通过我们的 Java 应用程序,我们演示了如何使用 Data Faker 库生成示例游戏角色数据并将其有效地插入 MongoDB。我们执行了基本操作,例如计算游戏角色的数量和检索特定的角色类型。此外,我们还在 Eclipse JNoSQL 中引入了存储库的概念,展示了它们在简化数据管理和基于字符类型实现集中查询方面的价值。本文为利用 Eclipse JNoSQL 和 MongoDB 的强大功能来简化 Java 应用程序中的 NoSQL 数据库交互奠定了坚实的基础,从而更轻松地管理和操作各种数据集。