NoSQL数据库为在数据库管理中存储和检索数据提供了一个灵活且可伸缩的选项。然而,他们可能需要面向对象编程范例方面的帮助,例如继承,这是Java等语言中的一个基本概念。本文探讨了在NoSQL数据库中处理继承时的阻抗不匹配问题。
NoSQL数据库中的继承挑战
术语“阻抗不匹配“指的是面向对象编程语言世界之间的脱节,如Java 语言(一种计算机语言,尤用于创建网站)和NoSQL数据库的表格、面向文档或基于图形的结构。这种不匹配特别明显的一个方面是处理继承。
在Java中,继承允许您创建类的层次结构,其中子类从其父类继承属性和行为。这一概念在Java编程中根深蒂固,经常用于对现实世界的关系进行建模。然而,NoSQL数据库没有连接,继承结构需要以不同的方式处理。
雅加达持久性(JPA)和继承战略
在深入探讨更高级的解决方案之前,值得一提的是有一些策略可以在Jakarta持久性(以前称为JPA)的世界中模拟关系数据库中的继承。这些战略包括:
联合遗传策略:在这种方法中,特定于子类的字段被映射到一个单独的表中,与父类的通用字段不同。需要时执行连接操作来实例化子类。
单表继承策略:该策略使用单个表来表示整个类层次结构。鉴别器列用于区分不同的子类。
表_每_类继承策略:层次结构中的每个具体实体类都对应于其在数据库中的表。
这些策略在关系数据库中运行良好,但不能直接应用于NoSQL数据库,主要是因为NoSQL数据库不支持传统的连接。
实时代码会话:Java SE、Eclipse JNoSQL和MongoDB
在本次实时代码会话中,我们将使用创建一个Java SE项目MongoDB作为我们的NoSQL数据库。我们将专注于管理游戏角色,特别是马里奥和索尼克角色,使用Eclipse JNoSQL。您可以使用以下命令在本地运行MongoDB码头工人或者在云中使用AtlasDB。我们将从数据库设置开始,然后继续Java代码实现。
在本地设置MongoDB
要在本地运行MongoDB,可以通过以下命令使用Docker:
docker run -d --name mongodb-instance -p 27017:27017 mongo
或者,您可以选择按照MongoDB AtlasDB提供的指令在云中执行它。
MongoDB数据库启动并运行后,让我们创建Java项目。
创建Java项目
我们将使用Maven和maven-原型-快速入门原型。该项目将利用以下技术和依赖关系:
雅加达CDI
雅加达JSONP
Eclipse微文件
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>
确保更换${jnosql.version}使用您打算使用的适当版本的Eclipse JNoSQL。
在下一节中,我们将继续实现我们的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();
}
在这段代码中:
我们用以下内容注释该类@Entity以表明它是我们MongoDB数据库中的一个持久实体。
我们使用@DiscriminatorColumn(“type”)指定名为“type”的鉴别器列将用于区分子类。
@Inheritance指示该类是继承层次结构的一部分。
这GameCharacter类具有唯一的标识符(id),角色名的属性(character)和游戏名称(game)和一个抽象方法getType(),它的子类将实现它来指定字符类型。
专业课:索尼克和马里奥
现在,让我们为Sonic和Mario实体创建专门化类。这些类将扩展游戏角色类,并提供特定于每个角色类型的附加属性。我们将使用@DiscriminatorValue若要定义这些值“type”每个子类可以接受的鉴别器列。
@Entity
@DiscriminatorValue("SONIC")
public class Sonic extends GameCharacter {
@Column
private String zone;
@Override
public GameType getType() {
return GameType.SONIC;
}
}
在声波课上:
我们用以下内容对其进行注释@Entity表明它是一个持久的实体。
@DiscriminatorValue(“SONIC”)指定“type”鉴别器列将具有值“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”)指定“类型”鉴别器列将具有值“MARIO”对于马里奥实体。
我们添加一个属性locations具体到马里奥角色。
这getType()方法返回GameType.MARIO,表示这是一个马里奥角色。
使用这种建模方法,您可以使用鉴别器列“type”轻松区分MongoDB数据库中的Sonic和Mario字符。
我们将使用Eclipse JNoSQL创建与MongoDB的第一个数据库集成。为了简化起见,我们将使用数据伪造库。我们的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容器并初始化DocumentTemplate来自Eclipse JNoSQL。
我们使用由DataFaker班级。
我们使用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"
}
]
如数据库结构所示,每个文档包含唯一标识符(_id)、角色名(character)、游戏名称(game)和一个鉴别器列type区分马里奥和索尼克角色。根据您生成的数据,您将在MongoDB数据库中看到更多字符。
该集成演示了如何使用Eclipse JNoSQL和MongoDB插入、计数和检索游戏角色。您可以根据需要扩展和增强该应用程序来管理和操作您的游戏角色数据。
我们将使用Eclipse JNoSQL创建用于管理游戏角色的存储库。我们将有一个普通游戏角色和一个控制台存储库SonicRepository专门针对音速角色。这些存储库将允许我们与数据库交互并轻松执行各种操作。
让我们为我们的游戏角色定义存储库。
控制台存储库
@Repository
public interface Console extends PageableRepository<GameCharacter, UUID> {
}
这Console知识库扩展PageableRepository用于一般的游戏角色。它提供了常见的CRUD操作和分页支持。
声波储存库
@Repository
public interface SonicRepository extends PageableRepository<Sonic, UUID> {
}
这SonicRepository延伸PageableRepository而是专门为声音角色设计的。它从父存储库中继承了常见的CRUD操作和分页。
主应用程序代码
现在,让我们修改我们的主要应用程序代码以使用这些存储库。
对于控制台存储库
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);
}
在这段代码中,我们使用控制台存储库来保存马里奥和索尼克角色,展示了它管理一般游戏角色的能力。
对于声波存储库
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专门保存声音角色。它展示了如何使用专用于特定字符类型的存储库。
使用这些存储库,您可以根据游戏角色的类型轻松管理、查询和过滤游戏角色,从而简化代码并使其更有条理。
结论
在本文中,我们使用Eclipse JNoSQL框架探索了MongoDB与Java的无缝集成,以实现高效的游戏角色管理。我们深入研究了游戏角色建模的复杂性,解决了与NoSQL数据库继承相关的挑战,同时保持了与Java面向对象原则的兼容性。通过使用鉴别器列,我们可以对字符进行分类并将其存储在MongoDB数据库中,从而创建一个结构良好且可扩展的解决方案。
通过我们的Java应用程序,我们演示了如何使用Data Faker库生成示例游戏角色数据并将其有效地插入MongoDB。我们执行了必要的操作,例如计算游戏角色的数量和检索特定的角色类型。此外,我们在Eclipse JNoSQL中引入了存储库的概念,展示了它们在简化数据管理和支持基于字符类型的重点查询方面的价值。本文为利用Eclipse JNoSQL和MongoDB的强大功能来简化Java应用程序中的NoSQL数据库交互提供了坚实的基础,使管理和操作各种数据集变得更加容易。